spring中如何实现代理

worktile 其他 22

回复

共3条回复 我来回复
  • fiy的头像
    fiy
    Worktile&PingCode市场小伙伴
    评论

    在Spring框架中,有多种方式可以实现代理。下面将介绍两种常用的方式:JDK动态代理和CGLIB代理。

    1. JDK动态代理
      JDK动态代理是通过反射机制实现的。在Java.lang.reflect包下,有一个Proxy类和InvocationHandler接口,它们是实现JDK动态代理的核心类和接口。

    首先,定义一个实现InvocationHandler接口的代理类,该类负责处理被代理类的方法调用,并在方法调用前后添加一些其他逻辑。比如:

    public class ProxyHandler implements InvocationHandler {
        private Object target; // 被代理的对象
    
        public ProxyHandler(Object target) {
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 在方法调用前添加逻辑
            System.out.println("Before method invocation");
    
            // 调用被代理对象的方法
            Object result = method.invoke(target, args);
    
            // 在方法调用后添加逻辑
            System.out.println("After method invocation");
    
            return result;
        }
    }
    

    然后,在使用代理的地方,使用Proxy类的静态方法newProxyInstance来创建代理对象。例如:

    public class Client {
        public static void main(String[] args) {
            // 创建被代理对象
            UserService userService = new UserServiceImpl();
    
            // 创建代理处理器
            ProxyHandler handler = new ProxyHandler(userService);
    
            // 创建代理对象
            UserService proxy = (UserService) Proxy.newProxyInstance(
                    userService.getClass().getClassLoader(),
                    userService.getClass().getInterfaces(),
                    handler
            );
    
            // 调用代理对象的方法
            proxy.addUser("Alice");
            proxy.deleteUser("Bob");
        }
    }
    
    1. CGLIB代理
      CGLIB(Code Generation Library)是一个强大的、高性能的代码生成库,它可以在运行时动态地生成指定代理类的子类,并通过方法拦截技术来拦截所有的目标类方法调用。

    首先,引入相关依赖:

    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.3.0</version>
    </dependency>
    

    然后,定义一个代理类,该类继承自MethodInterceptor接口,并实现其intercept方法。该方法可以在目标方法调用前后添加一些其他逻辑。例如:

    public class ProxyInterceptor implements MethodInterceptor {
        @Override
        public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            // 在方法调用前添加逻辑
            System.out.println("Before method invocation");
    
            // 调用目标对象的方法
            Object result = methodProxy.invokeSuper(target, args);
    
            // 在方法调用后添加逻辑
            System.out.println("After method invocation");
    
            return result;
        }
    }
    

    最后,在使用代理的地方,通过Enhancer类的create方法创建代理对象。例如:

    public class Client {
        public static void main(String[] args) {
            // 创建目标对象
            UserService userService = new UserServiceImpl();
    
            // 创建代理拦截器
            ProxyInterceptor interceptor = new ProxyInterceptor();
    
            // 创建Enhancer对象,并设置目标对象、回调拦截器
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(userService.getClass());
            enhancer.setCallback(interceptor);
    
            // 创建代理对象
            UserService proxy = (UserService) enhancer.create();
    
            // 调用代理对象的方法
            proxy.addUser("Alice");
            proxy.deleteUser("Bob");
        }
    }
    

    以上就是在Spring中实现代理的两种常用方式:JDK动态代理和CGLIB代理。可以根据实际需求选择适合的方式来实现代理。

    1年前 0条评论
  • worktile的头像
    worktile
    Worktile官方账号
    评论

    在Spring框架中,代理是一种常见的实现模式。Spring提供了几种方式来实现代理,包括基于JDK的动态代理和基于CGLIB的动态代理。以下是Spring中实现代理的几种方法:

    1. JDK动态代理:JDK动态代理是基于接口的代理方式。通过使用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口,可以动态地生成一个实现目标接口的代理类。代理类重写了目标接口的所有方法,并在方法中调用实际的目标对象方法之前或之后执行额外的逻辑。这种代理方式适用于具有接口的目标对象。

    2. CGLIB动态代理:CGLIB动态代理是基于类的代理方式。CGLIB是一个第三方库,它通过生成目标类的子类来创建代理。代理类继承了目标类,并重写了目标类的方法,以便在方法之前或之后执行额外的逻辑。这种代理方式适用于没有接口的目标对象。

    3. XML配置:Spring框架还提供了使用XML配置代理的方式。通过在Spring配置文件中定义<aop:config>标签和<aop:aspect>标签,可以配置切面和切点,并将代理引用到目标对象上。这种配置方式相对简单,但需要手动编写XML配置文件。

    4. 注解配置:除了XML配置外,Spring还支持使用注解配置代理。通过在目标对象上添加@EnableAspectJAutoProxy注解,并在切面类上使用@Aspect注解,可以配置切面和切点,并将代理引用到目标对象上。这种配置方式简化了配置过程,使代码更加简洁和易读。

    5. 编程方式:在某些情况下,可能需要在代码中直接编程实现代理。Spring提供了ProxyFactoryProxyFactoryBean等类,可以通过编程方式创建代理对象,并配置切面和切点。这种方式适用于需要更灵活和动态控制代理生成的场景。

    总结起来,Spring框架中实现代理的方式主要包括JDK动态代理、CGLIB动态代理、XML配置、注解配置和编程方式。开发者可以根据具体情况选择适合的方式来实现代理。无论哪种方式,代理都可以在目标对象的方法执行前后添加额外的逻辑,实现切面功能,提供更加灵活和可管理的代码结构。

    1年前 0条评论
  • 不及物动词的头像
    不及物动词
    这个人很懒,什么都没有留下~
    评论

    在Spring中,代理是实现面向切面编程(AOP)的重要手段。通过使用代理,可以在目标方法的前后添加额外的逻辑,例如日志记录、性能监控等。Spring提供了两种代理方式:JDK动态代理和CGLIB代理。

    1. JDK动态代理
      JDK动态代理是基于接口的代理,在运行时通过反射机制动态生成代理类。在Spring中,要使用JDK动态代理,需要满足以下条件:
    • 目标类必须实现至少一个接口。
    • 使用Spring的AOP命名空间或通过编程的方式配置切面。
    • 切面的通知方法需要实现接口org.aopalliance.aop.Advice。

    下面是使用JDK动态代理的步骤:
    1)定义接口

    public interface UserService {
        void addUser(String name);
    }
    

    2)实现目标类

    public class UserServiceImpl implements UserService {
        public void addUser(String name) {
            System.out.println("Add user: " + name);
        }
    }
    

    3)编写切面类

    public class LogAspect implements Advice {
        public void before() {
            System.out.println("Before method");
        }
      
        public void after() {
            System.out.println("After method");
        }
    }
    

    4)配置Spring的AOP命名空间或通过编程的方式配置切面
    使用AOP命名空间配置切面的方式如下:

    <aop:config>
        <aop:aspect ref="logAspect">
            <aop:before method="before" pointcut="execution(* com.example.UserService.addUser(..))" />
            <aop:after method="after" pointcut="execution(* com.example.UserService.addUser(..))" />
        </aop:aspect>
    </aop:config>
    

    通过编程的方式配置切面的方式如下:

    @Configuration
    @EnableAspectJAutoProxy
    public class AppConfig {
        @Bean
        public UserService userService() {
            return new UserServiceImpl();
        }
      
        @Bean
        public LogAspect logAspect() {
            return new LogAspect();
        }
      
        @Bean
        public Advisor logAdvisor(LogAspect logAspect) {
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* com.example.UserService.addUser(..))");
            return new DefaultPointcutAdvisor(pointcut, logAspect);
        }
    }
    

    通过以上配置,就可以实现目标方法的前后添加额外的逻辑。

    1. CGLIB代理
      CGLIB代理是基于类的代理,使用字节码生成技术动态生成子类来代理目标类。在Spring中,要使用CGLIB代理,需要满足以下条件:
    • 目标类不能被final修饰。
    • 使用Spring的AOP命名空间或通过编程的方式配置切面。
    • 切面的通知方法不需要实现接口。

    下面是使用CGLIB代理的步骤:
    1)定义目标类

    public class UserService {
        public void addUser(String name) {
            System.out.println("Add user: " + name);
        }
    }
    

    2)编写切面类

    public class LogAspect {
        public void before() {
            System.out.println("Before method");
        }
      
        public void after() {
            System.out.println("After method");
        }
    }
    

    3)配置Spring的AOP命名空间或通过编程的方式配置切面
    使用AOP命名空间配置切面的方式如下:

    <aop:config>
        <aop:aspect ref="logAspect">
            <aop:before method="before" pointcut="execution(* com.example.UserService.addUser(..))" />
            <aop:after method="after" pointcut="execution(* com.example.UserService.addUser(..))" />
        </aop:aspect>
    </aop:config>
    

    通过编程的方式配置切面的方式如下:

    @Configuration
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    public class AppConfig {
        @Bean
        public UserService userService() {
            return new UserService();
        }
      
        @Bean
        public LogAspect logAspect() {
            return new LogAspect();
        }
      
        @Bean
        public Advisor logAdvisor(LogAspect logAspect) {
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* com.example.UserService.addUser(..))");
            return new DefaultPointcutAdvisor(pointcut, logAspect);
        }
    }
    

    通过以上配置,就可以实现目标方法的前后添加额外的逻辑,并且使用CGLIB生成代理类。

    需要注意的是,JDK动态代理和CGLIB代理的选择取决于目标类是否实现了接口以及是否被final修饰。如果目标类实现了接口且未被final修饰,可以使用JDK动态代理。否则,需要使用CGLIB代理。

    1年前 0条评论
注册PingCode 在线客服
站长微信
站长微信
电话联系

400-800-1024

工作日9:30-21:00在线

分享本页
返回顶部