AOP的攔截功能是由java中的動態代理來實現的。說白了,就是在目標類的基礎上增長切面邏輯,生成加強的目標類(該切面邏輯或者在目標類函數執行以前,或者目標類函數執行以後,或者在目標類函數拋出異常時候執行。不一樣的切入時機對應不一樣的Interceptor的種類,如BeforeAdviseInterceptor,AfterAdviseInterceptor以及ThrowsAdviseInterceptor等)。那麼動態代理是如何實現將切面邏輯(advise)織入到目標類方法中去的呢?下面咱們就來詳細介紹並實現AOP中用到的兩種動態代理。AOP的源碼中用到了兩種動態代理來實現攔截切入功能:jdk動態代理和cglib動態代理。兩種方法同時存在,各有優劣。jdk動態代理是由java內部的反射機制來實現的,cglib動態代理底層則是藉助asm來實現的。總的來講,反射機制在生成類的過程當中比較高效,而asm在生成類以後的相關執行過程當中比較高效(能夠經過將asm生成的類進行緩存,這樣解決asm生成類過程低效問題)。還有一點必須注意:jdk動態代理的應用前提,必須是目標類基於統一的接口。若是沒有上述前提,jdk動態代理不能應用。由此能夠看出,jdk動態代理有必定的侷限性,cglib這種第三方類庫實現的動態代理應用更加普遍,且在效率上更有優點。java
1.定義接口和實現接口apache
package com.xiaoqiang.design; public interface Person { public void buy(); public void buy1(); }
package com.xiaoqiang.design; public class xiaoQiang implements Person { private String name; private String house; public xiaoQiang(String name, String house) { this.name = name; this.house = house; } @Override public void buy() { System.out.println(name+"買了"+house); } @Override public void buy1() { System.out.println("我是你爸爸"); } }
2.jdk動態代理的實現緩存
jdk動態代理是jdk原生就支持的一種代理方式,它的實現原理,就是經過讓target類和代理類實現同一接口,代理類持有target對象,來達到方法攔截的做用,這樣經過接口的方式有兩個弊端,一個是必須保證target類有接口,第二個是若是想要對target類的方法進行代理攔截,那麼就要保證這些方法都要在接口中聲明,實現上略微有點限制。maven
package com.xiaoqiang.design; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxySaler implements InvocationHandler { public Person person; public Object newInstall(Person person) { this.person=person; return Proxy.newProxyInstance(person.getClass().getClassLoader(),person.getClass().getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("執行方法前的操做"); if(method.getName().equals("buy")) { person.buy(); } if(method.getName().equals("buy1")) { person.buy1(); } System.out.println("執行方法後的操做"); return null; } }
3.運行類ide
package com.xiaoqiang.design; import sun.misc.ProxyGenerator; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class TestMain { public static void main(String[] args) { ProxySaler proxySaler=new ProxySaler(); Person object= (Person) proxySaler.newInstall(new xiaoQiang("黃豪強","南山區")); object.buy1(); object.buy(); /* byte[] bytes=ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{object.getClass()}); try { OutputStream outputStream=new FileOutputStream("$abc.txt"); outputStream.write(bytes); outputStream.flush(); outputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }*/ /* System.out.println(aa);*/ /*try{ System.out.println(object.getClass().getMethod("buy",Person.class)); } catch (Exception e) { System.out.println("異常"); }*/ /* object.buy1();*/ } }
Cglib方法的動態代理:函數
須要導入Cglib的jar包:this
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.xiaoqiang</groupId> <artifactId>cglibproxy</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.12</version> </dependency> </dependencies> </project>
1.定義被代理的方法:spa
/** * @author 黃豪強 * @create 2019/7/24 8:51 */ public class PlayGame { public void play() { System.out.println("打籃球很厲害"); } }
2.代理類代理
import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * @author 黃豪強 * @create 2019/7/24 8:51 */ public class CglibProxy implements MethodInterceptor { public Object newInstall(Object object) { return Enhancer.create(object.getClass(), this); } public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("先熱身一會"); methodProxy.invokeSuper(o,objects); System.out.println("打完了"); return null; } }
3.運行類code
/** * @author 黃豪強 * @create 2019/7/24 9:09 */ public class ProxyTeest { public static void main(String[] args) { CglibProxy cglibProxy=new CglibProxy(); PlayGame playGame= (PlayGame) cglibProxy.newInstall(new PlayGame()); playGame.play(); } }
4.運行結果