jdk動態代理和Cglib字節碼加強

JDK動態代理

利用攔截器加上反射機制生成一個實現代理接口的匿名類,在調用具體方法時,調用InvocationHandler來處理ide

JDK動態代理只須要JDK環境就能夠進行代理,流程爲:測試

  1. 實現InvocationHandlerthis

  2. 使用Proxy.newProxyInstance產生代理對象spa

  3. 被代理的對象必須實現接口代理

具體列子以下:code

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文件,修改其字節碼生成子類的方式完成,不須要實現接口blog

  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代理

相關文章
相關標籤/搜索