jdk动态代理和Cglib字节码增强


JDK动态代理

利用拦截器加上反射机制生成一个实现代理接口的匿名类,在调用具体方法时,调用InvocationHandler来处理

JDK动态代理只需要JDK环境就可以进行代理,流程为:

  1. 实现InvocationHandler

  2. 使用Proxy.newProxyInstance产生代理对象

  3. 被代理的对象必须实现接口

具体列子如下:

public class UserServiceImpl implements UserService { @Override public void eat() { System.out.println("---------吃饭"); } @Override public void wc() { System.out.print("上茅房------>"); } }
//切面类
public class MyAspect { public void before(){ System.out.print("先洗手再"); } public void after(){ System.out.print("后要洗手"); } }
// 产生代理对象的工厂类
public class MyFactoryBean { public static UserService getInstance(){ // target : 目标类
        final UserService service = new UserServiceImpl(); // Aspect : 切面类
        final MyAspect aspect = new MyAspect(); // Weaving : 织入,也就是产生代理的过程
        UserService proxy = (UserService) Proxy.newProxyInstance( MyFactoryBean.class.getClassLoader(), new Class[]{UserService.class}, new InvocationHandler(){ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("eat")){ aspect.before(); } Object invoke = method.invoke(service, args); if (method.getName().equals("wc")){ aspect.after(); } return invoke; } }); return proxy; } }
//测试方法
@Test public void userTest(){ UserService userService = MyFactoryBean.getInstance();  //使用工厂类产出代理对象
 userService.eat(); userService.wc(); }

效果如下:

CGLIB动态代理

  1. 通过加载对象类的class文件,修改其字节码生成子类的方式完成,不需要实现接口

  2. 但是需要第三方库:CGLIB类库的支持

public class MyProxy implements MethodInterceptor { ​ private Object personService; public Object createProxy(Object obj){ this.personService = obj; Enhancer e = new Enhancer(); e.setSuperclass(obj.getClass()); e.setCallback(this); Object proxy = e.create(); return proxy;   //返回代理对象
 } ​ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { Object obj = null; if ("eat".equals(method.getName())){ System.out.print("先洗手再----->"); } ​ obj = method.invoke(personService, objects); if ("wc".equals(method.getName())){ System.out.print("---->之后要洗手"); } return obj; } }
public class PeopleService {
public void eat(){
System.out.println("吃饭");
}
public void wc(){
System.out.print("上厕所");
}
}
@Test public void Test1(){ MyProxy myProxy = new MyProxy(); PeopleService proxy =(PeopleService) myProxy.createProxy(new PeopleService()); proxy.eat(); 

效果如下:

      

总结

关于在Spring的AOP中采用何种代理手段,我们不强加限制的话,会根据类是否有接口来区别对待

  1. 当一个类有接口的时候,就会选用JDK的动态代理

  2. 当一个类没有实现接口的时候,就会选用CGLIB代理的方式

两种代理方式的本质:

  1. JDK动态代理是针对实现了接口的类生成代理,不是针对类

  2. CGLIB使用的是为被代理类生成一个子类,通过继承的方法覆盖并增强其方法,

    但是因为是继承所以不能声明被代理类为final,无法被继承无法实现CGLIB代理


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM