8.Spring AOP的概述和实现原理
1.AOP
1.1 AOP概述
- AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编 译方式和运行期动态代理实现程序功能的统一维护的一种技术。
- AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
- 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
- AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码。
- 经典应用场景:事务管理,性能监视,安全检查,缓存,日志等
- Spring AOP使用纯JAVA实现,不需要专门的编译过程和类加载器,在运行期间通过代理方式向目标类织入增强代码。
- AspectJ是一个基于Java语言的AOP编程框架,spring从2.0开始,Spring AOP引入对Aspect的支持,Aspect扩展了java语言,提供了一个专门的编译器,在编译时提供横向代码的织入。
1.2 AOP实现原理
- aop底层将采用代理机制进性实现
- 接口+实现类:可以采用jdk的动态代理Proxy
- 有接口的实现类和没有接口的类:都可以采用cglib字节码增强来实现。
1.3 AOP术语
- target:目标类,需要配代理的类。例如:UserService
- joinpoint(连接点):所谓连接点就是指那些可能被拦截的方法。例如:所有的方法
- pointCut切入点:已经被增强的连接点。例如:addUser()
- advice通知/增强:增强代码。例如:after,before
- weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程。
- proxy代理类
- Aspect(切面):是切入点poinCut和advice的结合
====================================================================
Spring AOP原理之动态代理
■问题:--代理模式(Proxy--代理角色、Subject--抽象主题角色、RealSubject--主体角色)(代购火车票)
在实际的软件开发中,我们经常面临着对一个对象进行访问控制的问题,由于跨越网络或安全方面等原因不能直接或不需要直接被访问,直接访问的代价会给系统带来不必要的复杂性。那么怎么解决该问题呢????
如何在客户端程序与目标对象之间增加一层中间层,通过它来代替目标对象来完成客户程序对目标程序对象的各种操作要求,如此客户程序就可以透明的与目标对象进行交互?这是就需要用到代理模式。
引入的对新对象来实现对真实对象的操作或者是将新的对象作为真实对象的一个替身,这种实现机制即为代理模式。
通过票务中心买火车票,我们知道票务中心并不卖票,只有火车站才真正卖票,票务中心只是代理,票务中心卖的票其实是到火车站买的。
在这个例子中,你就是客户,票务中心就是代理角色,火车站就是具体主体角色,卖票称为抽象主题角色。
什么是代理?
指为一个目标对象提供一个代理对象,并由代理对象控制目标对象的引用,使用代理对象,是为了在不修改目标对象的基础上,增强目标对象的业务逻辑。

静态代理
静态代理的特点是,为每一个业务增强都提供一个代理类,由代理类来创建代理对象,下面我们通过静态代理来实现对转账业务进行身份验证。
(1).转账业务 (subject:抽象主题角色)
1 package com.iwakan.test.proxyDemo; 2 3 public interface IAccountService { 4 //主业务逻辑:转账 5 void transfer(); 6 }
(2).转账业务(RealSubject:主题角色)
1 package com.iwakan.test.proxyDemo; 2 3 public class AccountServiceImpl implements IAccountService { 4 @Override 5 public void transfer() { 6 System.out.println("调用dao层,完成转账"); 7 } 8 }
(3).代理类(proxy)
1 package com.iwakan.test.proxyDemo; 2 3 public class AccountProxy implements IAccountService { 4 //目标对象 5 private IAccountService target; 6 7 8 public AccountProxy(IAccountService target) { 9 this.target = target; 10 } 11 12 /** 13 * 代理方法,实现对目标对象的功能增强 14 */ 15 @Override 16 public void transfer() { 17 before(); 18 target.transfer(); 19 } 20 21 /** 22 * 前置增强 23 */ 24 private void before() { 25 System.out.println("对转账人身份进行验证。。"); 26 27 } 28 }
(4).测试
1 package com.iwakan.test.proxyDemo; 2 3 public class main { 4 public static void main(String[] args) { 5 //创建目标对象 6 IAccountService target = new AccountServiceImpl(); 7 //创建代理对象 8 AccountProxy proxy = new AccountProxy(target); 9 10 proxy.transfer(); 11 } 12 }
结果:
对转账人身份进行验证
调用dao层,完成转账业务
动态代理
静态代理会为每一个业务增强都提供一个代理类,由代理类来创建对象,而动态代理并不存在代理类,代理类直接由代理工具动态生成
JDK动态代理
jdk动态代理是使用java.lang.reflect包下的代理类来实现,jdk动态代理必须有接口
(1).转账业务 (subject:抽象主题角色)
1 package com.iwakan.test.proxyDemo;
2
3 public interface IAccountService {
4 //主业务逻辑:转账
5 void transfer();
6 }
(2).转账业务(RealSubject:主题角色)
1 package com.iwakan.test.proxyDemo;
2
3 public class AccountServiceImpl implements IAccountService {
4 @Override
5 public void transfer() {
6 System.out.println("调用dao层,完成转账");
7 }
8 }
(3).增强
因为这里没有配置切入点,称为切面会有点奇怪,所以称为增强
1 package com.iwakan.test.proxyDemo; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 public class AccountAdvice implements InvocationHandler { 7 //目标对象 8 private IAccountService target; 9 10 public AccountAdvice(IAccountService target){ 11 this.target = target; 12 } 13 14 /** 15 * 代理方法:每次调用目标方法时都会进到这里 16 * @param proxy 17 * @param method 18 * @param args 19 * @return 20 * @throws Throwable 21 */ 22 @Override 23 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 24 before(); 25 method.invoke(target,args); 26 return null; 27 } 28 29 /** 30 * 前置增强 31 */ 32 private void before() { 33 System.out.println("对转账人身份进行验证。。"); 34 } 35 }
(4).测试
1 package com.iwakan.test.proxyDemo; 2 3 import java.lang.reflect.Proxy; 4 5 public class main1 { 6 public static void main(String[] args) { 7 //创建目标对象 8 IAccountService target = new AccountServiceImpl(); 9 //创建代理对象 10 IAccountService proxyInstance = (IAccountService) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new AccountAdvice(target)); 11 proxyInstance.transfer(); 12 } 13 }
结果:
对转账人身份进行验证
调用dao层,完成转账业务
CGLIB动态代理
JDK动态代理必须有接口,但如果代理一个没有接口的类该怎么办呢?
这时我们可以使用CGLIB动态代理。
CGLIB动态代理的原理是生成目标类的子类,这个子类对象就是代理对象,代理对象是被增强过的。
注意:不管有没接口都可以使用CGLIB动态代理,而不是只有在无接口的情况下才可以使用
(1).转账业务
1 package com.iwakan.test.proxyDemo; 2 3 public class AccountService1 { 4 public void transfer(){ 5 System.out.println("调用dao层,完成转账业务"); 6 } 7 }
(2).增强
因为这里没有配置切入点,称为切面会有点奇怪,所以称为增强
1 package com.iwakan.test.proxyDemo; 2 3 import org.springframework.cglib.proxy.MethodInterceptor; 4 import org.springframework.cglib.proxy.MethodProxy; 5 6 import java.lang.reflect.Method; 7 8 public class AccountAdvice1 implements MethodInterceptor { 9 /** 10 * 代理方法:每次调用目标方法时都会进到这里 11 * @param obj 12 * @param method 13 * @param args 14 * @param methodProxy 15 * @return 16 * @throws Throwable 17 */ 18 @Override 19 public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { 20 before(); 21 return methodProxy.invokeSuper(obj,args); 22 } 23 24 /** 25 * 前置增强 26 */ 27 private void before() { 28 System.out.println("对转账人身份进行验证"); 29 } 30 }
测试
1 package com.iwakan.test.proxyDemo; 2 3 import org.springframework.cglib.proxy.Enhancer; 4 5 public class main1 { 6 public static void main(String[] args) { 7 //创建目标对象 8 AccountService1 target = new AccountService1(); 9 //创建代理对象 10 AccountService1 proxy = (AccountService1)Enhancer.create(target.getClass(), target.getClass().getInterfaces(), new AccountAdvice1()); 11 proxy.transfer(); 12 } 13 14 }
结果:
对转账人身份进行验证
调用dao层,完成转账业务

浙公网安备 33010602011771号