spring中如何实现代理
-
在Spring框架中,有多种方式可以实现代理。下面将介绍两种常用的方式:JDK动态代理和CGLIB代理。
- 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"); } }- 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年前 - JDK动态代理
-
在Spring框架中,代理是一种常见的实现模式。Spring提供了几种方式来实现代理,包括基于JDK的动态代理和基于CGLIB的动态代理。以下是Spring中实现代理的几种方法:
-
JDK动态代理:JDK动态代理是基于接口的代理方式。通过使用
java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口,可以动态地生成一个实现目标接口的代理类。代理类重写了目标接口的所有方法,并在方法中调用实际的目标对象方法之前或之后执行额外的逻辑。这种代理方式适用于具有接口的目标对象。 -
CGLIB动态代理:CGLIB动态代理是基于类的代理方式。CGLIB是一个第三方库,它通过生成目标类的子类来创建代理。代理类继承了目标类,并重写了目标类的方法,以便在方法之前或之后执行额外的逻辑。这种代理方式适用于没有接口的目标对象。
-
XML配置:Spring框架还提供了使用XML配置代理的方式。通过在Spring配置文件中定义
<aop:config>标签和<aop:aspect>标签,可以配置切面和切点,并将代理引用到目标对象上。这种配置方式相对简单,但需要手动编写XML配置文件。 -
注解配置:除了XML配置外,Spring还支持使用注解配置代理。通过在目标对象上添加
@EnableAspectJAutoProxy注解,并在切面类上使用@Aspect注解,可以配置切面和切点,并将代理引用到目标对象上。这种配置方式简化了配置过程,使代码更加简洁和易读。 -
编程方式:在某些情况下,可能需要在代码中直接编程实现代理。Spring提供了
ProxyFactory和ProxyFactoryBean等类,可以通过编程方式创建代理对象,并配置切面和切点。这种方式适用于需要更灵活和动态控制代理生成的场景。
总结起来,Spring框架中实现代理的方式主要包括JDK动态代理、CGLIB动态代理、XML配置、注解配置和编程方式。开发者可以根据具体情况选择适合的方式来实现代理。无论哪种方式,代理都可以在目标对象的方法执行前后添加额外的逻辑,实现切面功能,提供更加灵活和可管理的代码结构。
1年前 -
-
在Spring中,代理是实现面向切面编程(AOP)的重要手段。通过使用代理,可以在目标方法的前后添加额外的逻辑,例如日志记录、性能监控等。Spring提供了两种代理方式:JDK动态代理和CGLIB代理。
- 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); } }通过以上配置,就可以实现目标方法的前后添加额外的逻辑。
- 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年前 - JDK动态代理