本篇文章會詳細的介紹AOP的實現過程。AOP的實現原理在上一篇博客中已經提到。java
AOP面向切面的編程。他的主要實現是經過代理實現。網上有許多有關於代理的實現。咱們一步一步來,從最簡單到最複雜。spring
除了第一例子外。其餘都是以 接口 目標類 代理類 mian函數的結構。express
1.簡單代理(結構圖和代碼)編程
classA代碼ide
public class classA { public void request() { // TODO Auto-generated method stub System.out.println("classA request"); } }
用來代理classA的代理類 proxyclassA函數
public class proxyclassA { private classA classa; String a; public proxyclassA(classA classa) { // TODO Auto-generated constructor stub this.classa=classa; } public void request() { // TODO Auto-generated method stub System.out.println("執行request以前\n"); classa.request(); System.out.println("執行request以後\n"); } }
main類this
public class main { public static void main(String[] args) { // TODO Auto-generated method stub classA classa=new classA(); proxyclassA proxyclassa=new proxyclassA(classa); proxyclassa.request(); } }
上面是一個「毫無用處」的代理。現實中不多代碼會這麼寫。 可是aop 的編程思想在這裏已經開始顯現。spa
上面代理類最突出的一個問題是:每寫一個類都須要創建一個代理類。代理
2.我在上面基礎上加上一個接口。以下(結構圖和代碼)code
//接口 public interface subjectj { void request(); } //目標類 public class classA implements subjectj{ public void request() { // TODO Auto-generated method stub System.out.println("classA request"); } } //代理類proxyclassA public class proxyclassA implements subjectj{ private subjectj subjectj; String a; public proxyclassA(subjectj subjectj) { // TODO Auto-generated constructor stub this.subjectj=subjectj; } public void request() { // TODO Auto-generated method stub System.out.println("執行request以前\n"); subjectj.request(); System.out.println("執行request以後\n"); } } // mian 函數 public class main { public static void main(String[] args) { classA classa=new classA(); subjectj proxyclassa=new proxyclassA(classa); proxyclassa.request(); } }
以上就是靜態代理,靜態代理是不須要經過接口實現的。爲了與動態代理比較才加上去接口。同時加上接口後咱們發現,咱們不須要爲每個目標類創建一個代理類。咱們只須要保證代理類和目標類繼承同一個接口。可是這樣依然不夠好。由於他們須要繼承同一個接口,一旦接口多了,須要的代理類就會變多。
3.下面是動態代理。
//實現一個接口 public interface isubject { public void request(); } //目標類,須要被代理的類 public class Realsubject implements isubject { @Override public void request() { // TODO Auto-generated method stub System.out.println("realsubject request"); } } //實現代理的類 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class ProxySubject implements InvocationHandler{ private Object obj; public ProxySubject() { // TODO Auto-generated constructor stub } public ProxySubject(Object obj) { this.obj=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println( " before calling " + method); method.invoke(obj,args); System.out.println( " after calling " + method); return null; } } //mian函數 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class mainpro { public static void main(String[] args) { Realsubject rs = new Realsubject(); // 在這裏指定被代理類 InvocationHandler ds = new ProxySubject(rs); Class cls = rs.getClass(); // 如下是一次性生成代理 isubject subject = (isubject) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),ds ); subject.request(); } }
動態代理真正實現了多個目標類一個代理類。可是代理類要作的規範不少。同時動態代理類須要實現接口,也難以實現代理多樣化(同一個類中每一個方法都有不一樣的代理)。
4.咱們使用代理是爲了實現aop編程。但上面依然不能解決咱們編寫代碼的負重。尤爲是上面的問題,爲了解決問題,我決定引入spring。
首先,咱們採用spring AOP 有兩種方式。一種是常規JDK,一種是CGLIB。jdk就是我上面說的動態代理。CGLIB是另外一種方式。這兩種方式有什麼區別?
一、若是目標類實現了接口,默認狀況下會採用JDK的動態代理實現AOP
二、若是目標類實現了接口,能夠強制使用CGLIB實現AOP
三、若是目標類沒有實現了接口,必須採用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換
這樣,咱們就解決了一個問題。目標類不須要必定實現接口。
spring爲咱們提供編寫代碼的兩種方式:註解,文件配置。不管是jdk仍是CGLIB均可以用這兩種方式實現。
看代碼:
//接口 public interface Aservice { public void fooA(String _msg); } //目標類 public class AseviceImpl implements Aservice{ public void fooA(String _msg) { // TODO Auto-generated method stub System.out.println(_msg); } public void barA() { System.out.println("AServiceImpl.barA()"); } } //代理類,這裏就不應叫他代理類了。應該是切面類 import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @Aspect public class TestAspect { //須要針對的方法 exexution 返回值 包.類 .方法(參數) @Pointcut("execution(* sprigaop.AseviceImpl.*(..))") private void pointCutMethod() { } //在該方法以後作什麼 @After("pointCutMethod()") public void doAfter(JoinPoint jp) { System.out.println("log Ending method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName()); } //環繞該方法作什麼 @Around("pointCutMethod()") public Object doAround(ProceedingJoinPoint pjp) throws Throwable { long time = System.currentTimeMillis(); Object retVal = pjp.proceed(); time = System.currentTimeMillis() - time; System.out.println("process time: " + time + " ms"); return retVal; } //在該方法以前作什麼 @Before("pointCutMethod()") public void doBefore(JoinPoint jp) { System.out.println("log Begining method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName()); } } //mian主函數 import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; public class main { public static void main(String[] args) { // TODO Auto-generated method stub BeanFactory b = new ClassPathXmlApplicationContext("spring.xml"); //注意有接口目標類。須要使用接口獲取 Aservice as=(Aservice)b.getBean("aService"); as.fooA("hello"); } }
配置文件spring.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> <aop:aspectj-autoproxy proxy-target-class="true"/> <bean id="aspectBean" class="com.spring.service.TestAspect" /> <bean id="aService" class="sprigaop.AseviceImpl"></bean> </beans>
是否是很清晰。尤爲是切面類(原來是代理類,真正的代理類已經隱藏了)中。針對哪個函數方法。在此以前執行什麼,在此以後執行什麼。一目瞭然。使用註解的方式代理。只須要在配置文件中加入自動代理:<aop:aspectj-autoproxy />
那麼上面是哪種代理呢?答案是CGLIB,儘管這個類實現了接口。但咱們在配置文件中將他強制使用了CGLIB。代碼:proxy-target-class="true"
去掉proxy-target-class="true"後就是使用JDK來實現AOP
細節:有接口和無接口的代理,main裏面獲取是不同的。有藉口的使用接口獲取目標對象,無接口使用類獲取目標對象。
下一個例子代碼:
//接口 //目標類 public class AseviceImpl { public void fooA(String _msg) { // TODO Auto-generated method stub System.out.println(_msg); } public void barA() { System.out.println("AServiceImpl.barA()"); } } //代理類 import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @Aspect public class TestAspect { public void doAfter(JoinPoint jp) { System.out.println("log Ending method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName()); } public Object doAround(ProceedingJoinPoint pjp) throws Throwable { long time = System.currentTimeMillis(); Object retVal = pjp.proceed(); time = System.currentTimeMillis() - time; System.out.println("process time: " + time + " ms"); return retVal; } public void doBefore(JoinPoint jp) { System.out.println("log Begining method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName()); } } //mian主函數 import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; public class main { public static void main(String[] args) { // TODO Auto-generated method stub BeanFactory b = new ClassPathXmlApplicationContext("spring.xml"); AseviceImpl as=(AseviceImpl)b.getBean("aService"); as.fooA("hello"); } }
配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> <aop:config> <aop:aspect id="TestAspect" ref="aspectBean"> <!--配置com.spring.service包下全部類或接口的全部方法--> <aop:pointcut id="businessService" expression="execution(* sprigaop.AseviceImpl.*(..))" /> <aop:before pointcut-ref="businessService" method="doBefore"/> <aop:after pointcut-ref="businessService" method="doAfter"/> <aop:around pointcut-ref="businessService" method="doAround"/> </aop:aspect> </aop:config> <bean id="aspectBean" class="com.spring.service.TestAspect" /> <bean id="aService" class="sprigaop.AseviceImpl"></bean> </beans>
此次是無接口,CGLIB ,配置文件的方式代理。