二、Spring AOP原理

学习内容

1、AOP简述

2、Spring AOP简介

3、Spring AOP设计

4、Spring AOP实现


 

一、AOP简述:

AOP:Aspct-Oriented Programming,意思为面向切面。AOP把软件系统分为两个部分:核心关注点和横切关注点。核销关注点即为业务代码,而横切关注点为业务无关代码,例如权限认证、日志、事务处理等。AOP技术有AspectJ、JBoss-AOP、Spring AOP等。

1、Aspect(切面):将影响了多个类的公共行为封装到一个可重用模块,该模块即为切面。

2、Joinpoint(连接点): 一个应用执行过程中能够插入一个切面的点。

SpringAOP的连接点只能是方法。

3、Pointcut(切点): 连接点的集合。

4、Advice(通知/增强):在特定的连接点,AOP框架执行的动作。描述切面要完成的工作,还解决何时执行这个工作。Spring 切面可应用的 5 种通知类型:

a、Before——在方法调用之前调用通知

b、After——在方法完成之后调用通知,无论方法执行成功与否

c、After-returning——在方法执行成功之后调用通知

d、After-throwing——在方法抛出异常后进行通知

e、Around——通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行

5、Introduction(引入):引入是一种特殊的增强,它为目标类添加一些属性和方法。

如果一个业务类没有实现某个接口,通过AOP的引介功能,可以动态地为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。

Spring允许引入新的接口到任何被通知的对象。例如,可以使用一个引入使任何对象实现 IsModified接口,来简化缓存。Spring中要使用Introduction, 可有通过DelegatingIntroductionInterceptor来实现通知,通过DefaultIntroductionAdvisor来配置Advice和代理类要实现的接口。

6、Target Object(目标对象): 包含连接点的对象。也被称作被通知或被代理对象。

7、Weave(织入): 织入是将切面应用到目标对象来创建的代理对象过程。根据不同的实现技术,AOP有三种织入的方式:

a、编译期织入,这要求使用特殊的Java编译器。

b、类装载期织入,这要求使用特殊的类装载器。

c、动态代理织入,在运行期为目标类添加增强生成子类的方式。

SpringAOP采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。


二、Spring AOP简介

1、Spring AOP对相关术语的实现

a、Advice

继承关系,以实现类MethodBeforeAdvice为例

 

实现MethodBeforeAdvice的before回调方法就行

public interface MethodBeforeAdvice extends BeforeAdvice {

void before(Method var1, Object[] var2, Object var3) throws Throwable;

}

Spring org.springframework.aop 下的其他Advice实现类,例如AfterReturningAdvice等,设计都是一致的。

b、Pointcut

继承关系,以实现类JdkRegexpMethodPointcut为例

 


public interface Pointcut {

    Pointcut TRUE = TruePointcut.INSTANCE;

    ClassFilter getClassFilter();
    
    MethodMatcher getMethodMatcher();

}
public interface MethodMatcher {

    MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;

    boolean matches(Method var1, Class<?> var2);

    boolean isRuntime();

    //当返回true时,表名当前方法需要增强。以JDK动态代理织入方式为例,该方法的
    //调用在,拦截接口的invoke()方法中调用
    boolean matches(Method var1, Class<?> var2, Object[] var3);

}

除了JdkRegexpMethodPointcut,还有NameMatchMethodPointcut,以方法名作为匹配

c、Advisor

用于结合,Advice和Pointcut,以DefaultPointcutAdvisor为例,继承关系为

 


三、Spring AOP设计

1、设计

Spring AOP的技术实现是以动态代理为基础,也就是说Spring AOP功能就是使用动态代理实现的。


四、Spring AOP实现

1、如何生成代理对象?ProxyCreatorSupport

继承关系

 

实现子类有三个

 

AspectJProxyFactory:支持集成AspectJ和Spring。

ProxyFactoryBean:支持在Ioc容器中完成声明配置Spring AOP.

ProxyFactory:支持编程式的使用Sprng AOP功能。

 

2、ProxyFactoryBean、ProxtyFactory实现AOP功能

使用ProxyFactoryBean,是Ioc环境中创建Aop应用的最底层方式,最为灵活。Spring通过ProxyFactoryBean完成对AOP功能的封装。

如何使用?

//定义一个接口

public interface UserDao {

    void addUser();

}

//目标对象实现接口并重写方法

public class UserDaoImpl implements UserDao {

    @Override
    public void addUser() {

        System.out.println("新增用户");

    }

}

//实现增强类的接口

public class LogBefore implements MethodBeforeAdvice {

    //arg0 目标类的方法
    arg1 目标类的入参数
    arg2 目标类
    @Override
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {

        System.out.println("添加日志");

    }

}

ProxtyFactory以编程形式

public class Test {

    public static void main(String[] args) throws Exception{

        LogBefore log = new LogBefore();

        UserDao userDao = new UserDaoImpl();

        ProxyFactory proxyf = new ProxyFactory();

        //设置目标对象
        proxyf.setTarget(userDao);

        //设置增强类对象
        proxyf.addAdvice(log);

        //获得代理对象
        UserDao up = proxyf.getProxy();

        up.addUser();

    }

}

ProxyFactoryBean通过xml配置代理。

<bean id="logBefore" class="com.cong.LogBefore"/>

<bean id="target" class="com.cong.UserDaoImpl"/>

<bean id="userDao" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.cong.UserDao"
p:interceptorNames="logBefore"
p:target-ref="target"/>

 

target:代理的目标对象

proxyInterfaces:代理所需要实现的接口,可以多个接口。该属性还有一个别名是Interfaces

interceptorNames:需要植入目标对象的bean列表。采用bean的名称指定。

这些bean必须实现类 org.aopalliance.intercept.MethodInterceptor

或 org.springframework.aop.Advisor的bean ,配置中的顺序对应调用的顺序。

proxyTargetClass:是否对类进行代理,而不是进行对接口进行代理。

设置为true时,使用CGLib代理,且proxyInterfaces属性被ProxyFactoryBean忽略。

 

3、代理对象的生成

ProxyFactoryBean为FactoryBean,所以,以getObject()为入口可知,代理对象的生成,由AopProxy生成,其实现类有两个,Cglib2AopProxy、JdkDynamicProxy,所以Spring分别通过CGLIB和JDK来生成代理对象。

而AopProxy的生成由DefaultAopProxyFactory来生成,具体生成哪个实现类由代理的模板类是否实现接口来判断,如果是则生成JdkDynamicAopProxy,否则使用Cglib2AopProxy,或者配置强制使用Cglib2AopProxy。这两个类都有直接实现各自代理的拦截器接口,如JdkDynamicAopProxy实现了InvocationHandler接口的invoke()方法,Cglib2AopProxy实现了DynamicAdvicedInterceptor接口的intercept()方法,所以Spring AOP具体的增强就是通过拦截器来完成的。

 

<think>好的,用户想了解Spring AOP原理,特别是代理模式、动态代理和静态代理。首先,我需要回顾一下代理模式的基本概念,然后区分静态代理和动态代理的不同,再联系到Spring AOP是如何应用这些技术的。 首先,代理模式的定义。根据引用[1],代理模式允许在不修改被代理对象的情况下,通过代理类进行功能增强。这里的关键是代理类分为静态和动态两种。静态代理需要手动创建代理类,而动态代理在运行时生成。用户可能想知道这两种代理在Spring AOP中的应用场景。 接下来,静态代理的细节。引用[1]提到静态代理的类在运行前已经存在,通常由程序员手动编写或工具生成。例如,假设有一个业务接口Subject和实现类RealSubject,静态代理类Proxy会实现Subject并持有RealSubject的引用,在方法调用前后添加逻辑。这种情况的缺点是每个被代理类都需要一个对应的代理类,导致代码冗余。 然后是动态代理,Spring AOP主要使用JDK动态代理和CGLIB。引用[2]指出JDK代理通过Proxy类生成代理对象,而CGLIB通过Enhancer创建。JDK动态代理要求目标类实现接口,利用InvocationHandler的invoke方法进行增强。CGLIB则通过继承目标类,重写方法来实现代理,适用于没有接口的情况。需要解释这两种方式的区别以及Spring如何选择使用哪一种。 还要结合Spring AOP的源码,如引用[2]提到的AOP源码剖析部分。Spring在运行时决定使用哪种代理方式,如果目标类实现了接口,默认使用JDK代理,否则使用CGLIB。这涉及到AOP的配置和底层机制。 用户可能还关心AOP的应用场景,比如事务管理、日志记录等,这些通过代理模式实现,无需修改原有代码。需要举例说明,比如在方法执行前后加入事务控制,动态代理如何拦截方法调用并添加额外操作。 另外,需要确保回答结构清晰,分点说明原理、代理类型、实现方式以及Spring的选择策略。同时,生成的相关问题要围绕用户可能进一步询问的点,比如性能比较、配置方法或实际应用例子。 最后,检查引用是否正确应用,如引用[1]关于代理模式的分类,引用[2]关于Spring AOP的具体实现,引用[3]关于代理模式的角色。确保每个技术点都有对应的引用支持,增加回答的可信度。</think>### Spring AOP原理与代理模式解析 #### 一、代理模式的核心作用 代理模式通过代理对象控制对真实对象的访问,在**不修改原始代码**的前提下实现功能增强。其核心角色包括: - **Subject**:定义业务接口(可以是接口或抽象类)[^3] - **RealSubject**:具体业务实现类(被代理对象) - **Proxy**:代理类,负责增强和控制对RealSubject的访问 #### 、静态代理的实现方式 静态代理需**手动编写代理类**,代理关系在编译时确定。例如: ```java // 业务接口 interface UserService { void save(); } // 真实对象 class UserServiceImpl implements UserService { public void save() { /* 业务逻辑 */ } } // 静态代理类 class UserServiceProxy implements UserService { private UserService target; public UserServiceProxy(UserService target) { this.target = target; } public void save() { System.out.println("前置增强"); target.save(); // 调用真实对象方法 System.out.println("后置增强"); } } ``` **缺点**:每个业务类需对应一个代理类,代码冗余度高[^1]。 #### 三、动态代理的实现机制 Spring AOP主要采用两种动态代理技术: 1. **JDK动态代理**(基于接口) - 要求目标类必须实现至少一个接口 - 通过`java.lang.reflect.Proxy`生成代理对象 - 核心类`InvocationHandler`实现方法拦截: ```java class JdkProxyHandler implements InvocationHandler { private Object target; public Object getProxy(Object target) { this.target = target; return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } public Object invoke(Object proxy, Method method, Object[] args) { System.out.println("前置增强"); Object result = method.invoke(target, args); System.out.println("后置增强"); return result; } } ``` 2. **CGLIB代理**(基于继承) - 通过生成目标类的子类实现代理 - 使用`MethodInterceptor`接口: ```java class CglibInterceptor implements MethodInterceptor { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) { System.out.println("前置增强"); Object result = proxy.invokeSuper(obj, args); System.out.println("后置增强"); return result; } } // 通过Enhancer创建代理 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(TargetClass.class); enhancer.setCallback(new CglibInterceptor()); TargetClass proxy = (TargetClass)enhancer.create(); ``` - **优势**:可代理无接口的类[^2] #### 四、Spring AOP的代理选择策略 | 条件 | 使用的代理方式 | |--------------------------|----------------| | 目标类实现了至少一个接口 | JDK动态代理 | | 目标类未实现任何接口 | CGLIB代理 | **底层实现**: - 通过`DefaultAopProxyFactory`类判断代理方式 - Spring Boot 2.x后默认强制使用CGLIB(可通过`spring.aop.proxy-target-class=true`配置) #### 五、AOP核心流程 1. 解析切面定义(@Aspect) 2. 匹配连接点(Pointcut) 3. 生成代理对象 4. 编织增强逻辑(Advice) 5. 通过责任链模式执行拦截器链 #### 六、性能对比 - **JDK动态代理**:生成速度快,执行效率稍低 - **CGLIB**:生成速度慢,执行效率高(现代JVM差距已不明显)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值