本篇文章会详细的介绍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 ,配置文件的方式代理。