@survivorZzz
2019-07-05T04:25:37.000000Z
字数 3476
阅读 517
spring
JDK的动态代理通常的步骤是:
1.有一个业务接口
public interface Subject {void doSomething();}
2.目标类实现该接口(因为JDK的动态代理必须要求目标类实现接口)
public class RealSubject implements Subject {@Overridepublic void doSomething() {System.out.println("RealSubject do something");}}
3.接着创建一个代理类JDKDynamicProxy实现java.lang.reflect.InvocationHandler接口,重写invoke方法.
public class JDKDynamicProxy implements InvocationHandler {private Object target;public JDKDynamicProxy(Object target) {this.target = target;}/*** 获取被代理接口实例对象* @param <T>* @return*/public <T> T getProxy() {return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Do something before");Object result = method.invoke(target, args);System.out.println("Do something after");return result;}}
4.测试看看:
public class Client {public static void main(String[] args) {// 保存生成的代理类的字节码文件System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");// jdk动态代理测试Subject subject = new JDKDynamicProxy(new RealSubject()).getProxy();subject.doSomething();}}输出结果:Do something beforeRealSubject do somethingDo something after
CGlib动态代理的步骤:
import java.lang.reflect.Method;import com.lf.shejimoshi.proxy.entity.UserManager;import com.lf.shejimoshi.proxy.entity.UserManagerImpl;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;//Cglib动态代理,实现MethodInterceptor接口public class CglibProxy implements MethodInterceptor {private Object target;//需要代理的目标对象//重写拦截方法@Overridepublic Object intercept(Object obj, Method method, Object[] arr, MethodProxy proxy) throws Throwable {System.out.println("Cglib动态代理,监听开始!");Object invoke = method.invoke(target, arr);//方法执行,参数:target 目标对象 arr参数数组System.out.println("Cglib动态代理,监听结束!");return invoke;}//定义获取代理对象方法public Object getCglibProxy(Object objectTarget){//为目标对象target赋值this.target = objectTarget;Enhancer enhancer = new Enhancer();//设置父类,因为Cglib是针对指定的类生成一个子类,所以需要指定父类enhancer.setSuperclass(objectTarget.getClass());enhancer.setCallback(this);// 设置回调Object result = enhancer.create();//创建并返回代理对象return result;}public static void main(String[] args) {CglibProxy cglib = new CglibProxy();//实例化CglibProxy对象UserManager user = (UserManager) cglib.getCglibProxy(new UserManagerImpl());//获取代理对象user.delUser("admin");//执行删除方法}}
在spring中如果目标类实现了接口, 则spring默认会使用JDK的动态代理来为目标类生成代理对象.如果目标类没有实现接口, 则会使用CGlib字节码生成技术为目标类生成一个子类的字节码来生成代理对象.
如果用户需要强制使用CGlib的方式来让spring为目标类生成代理对象, 则可以加入配置:
xml配置形式
<aop:aspectj-autoproxy proxy-target-class="true"/>
注解的形式
@Configuration@EnableAspectJAutoProxy(proxyTargetClass=true)public class AppConfig {// ...}
没有必要手动去添加CGlib的依赖包, 因为spring自3.2版本起就已经将CGlib的依赖repackge到了spring-core的lib中.
面向切面编程(AOP)有两种实现方式, 一种是Spring AOP(用动态代理技术JDK proxy和CGlib), 一种是AspectJ技术, 关于两者的优缺点. 个人认为如下中springboot引入Aspectj来实现aop, 仅仅只是使用了Aspectj的语义(如注解@Aspect等), 具体实现的时候还是使用了动态代理.
在springboot中使用AspectJ类型的AOP需要:
1.加入以下依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>
该依赖会引入和该版本的springboot最适配的org.aspectj.aspectjweaver的jar依赖, 所以就可以使用诸如@Aspect, @Before等属于Aspect的注解来做切面开发.
@Configuration@EnableAspectJAutoProxypublic class AppConfig {}
以上的@EnableAspectJAutoProxy的proxyTargetClass=true代表强制用CGlib的形式生成代理对象, false则使用默认用JDK的动态代理
xml配置的方式:
<aop:aspectj-autoproxy proxyTargetClass=true/>
以上为true同样强制使用CGlib的方式.
关于在spring中使用AOP参考官方文档.