需求:不改变原有类前提下添加日志管理等功能。(代码资源网址。。。http://download.csdn.net/download/zxc_helloworld/9999413)
aop理解第一步:静态代理 示例:LoginServiceStaticProxy.java
创建一个代理类,继承被代理类的接口。
在代理类中声明被代理对象。
实现接口的方法中,调用代理对象的方法,可在方法的前后添加代码实现功能扩展
在测试类中,调用代理对象的方法。
评价:静态代理确实实现了在不改变代码的情况下添加了功能,但是如果每一个方法和类都这样代理的话 ,我靠,那还不多的上天。动态代理可以解决该问题
aop理解第二步:JDK动态代理(针对接口)
创建一个类实现InvocationHandler接口
类中声明一个代理Object对象target用来接收要代理的对象
创建一个getProxyInstance(Object obj)方法接收要代理的对象,赋给target并且返回代理对象实例
在接口方法中实现功能扩展
在applicationContext.xml中配置代理
在测试类中进行测试。
另外:如果要实现相应方法才给扩展功能,可以在invoke扩展方法中判断method的名字或者有没有特殊注解来进行实现
评价:JDK动态代理实现了多个接口的代理,代理的对象都有相应接口,要是代理没有接口的类的话得使用CGLIB代理
aop理解第三步:CGLIB动态代理
创建代理类实现MethodInterceptor接口
创建一个getProxyInstance(Object obj)方法接收要代理的对象,使用Enhancer类进行操作
在MethodInterceptor接口提供的方法中实现功能扩展
在applicationContext.xml中配置代理
在测试类中进行测试。
评价:CGLIB实现了没有接口也可以代理,纵观两个动态代理都实现了为全部方法实现代理,但是为单个方法或者部分方法实现代理还是有些麻烦。
让我们来看看spring如何实现代理?
aop理解第四步:spring内置代理对象,spring内置的代理(ProxyFactoryBean)也是JDK动态代理,所以代理是针对接口的。使用举例:
首先创建一个要被代理的接口,以及它的实现类。
然后创建几个类(通知类)实现下面的接口:
MethodBeforeAdvice(前置通知,实现此接口中的方法,可在执行代理对象的方法前执行)
AfterReturingAdvice(后置通知)
MethodInterceptor(环绕通知)
ThrowsAdvice(异常通知)
(还有一个需配置的引入通知,只希望在调用某个函数时才出现通知)
然后在Xml中配置代理类ProxyFactoryBean。
在测试类中进行测试。
评价:不用自己手写代理类了,spring原来有内置的代理类啊,但是这样手动实现接口,是不是有点太麻烦了,spring其实也有实现上述接口的实现类。下面就来看一下
aop理解第五步:
aop理解第六步:Spring基于XML配置实现AOP
首先创建一个切面类,就是在里面配置要增加的功能方法。
配置XML。(切面,切入点,以及配置方法)
此外 SpringAOP和CGLIB代理冲突,具体原因我还没弄清,不过我看到下面这一句话:
Spring AOP的原理是 JDK 动态代理和CGLIB字节码增强技术,前者需要被代理类实现相应接口,也只有接口中的方法可以被JDK动态代理技术所处理;后者实际上是生成一个子类,来覆盖被代理类,那么父类的final方法就不能代理,因为父类的final方法不能被子类所覆盖。一般而言Spring默认优先使用JDK动态代理技术,只有在被代理类没有实现接口时,才会选择使用CGLIB技术来实现AOP。(http://blog.csdn.net/u014763172/article/details/52797045)
aop理解第七步:Spring基于注解配置实现AOP
不在XML中配置,直接在切面方法中设置注解来配置
@Before("execution(* cn.edu.sdut.aop.service.impl.S*2.*Say(..))")
@AfterReturning(value="execution(* cn.edu.sdut.aop.service.impl.S*2.*Say(..))",returning="obj")
@After("execution(* cn.edu.sdut.aop.service.impl.S*2.*Say(..))")
@AfterThrowing(value="execution(* cn.edu.sdut.aop.service.impl.S*2.*Say(..))",throwing="e")
@Around("execution(* cn.edu.sdut.aop.service.impl.S*2.*Say(..))")