Spring|Spring AOP 基础概念
Pointcut 切入点
pointcut是spring独有,非aop联盟定义。
pointcut定义描述匹配某个或某些类的方法。相当于把某个类或某些类的方法抽取出来一起描述。
pointcut独立于增强点(advice)之外,可重复使用,即一个切入点可以被不同的advice使用。
实现由多种
- 表达式匹配, 即定义表达式的方式匹配出切入点
- 控制流式,比如声明一个切入点,指定谁调用才触发增强, 其他方式调用不触发增强.
- 注解匹配等待
advice是aop联盟定义的,同时定义了interceptor为advice的子接口. 在spring中每个advice都是spring bean. 增强类型包括
- 前置增强
- 异常增强
- 后置增强
- 环绕增强
- 引入增强
引入增强(introduction advice)spring把引入增强视为一种特殊的增强拦截, 它为类添加一些属性和方法。引入增强不能和pointcut组合,引入增强只能作用于类,不能作用于方法上。
这样,即一个业务类原本没有实现某个接口,通过引介功能,可以动态的为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。
spring中Advisor是一个advice关联一个pointcut的组合描述对象。
ProxyFactory 代理工厂
【Spring|Spring AOP 基础概念】提供创建代理对象的工厂,依赖Advisor
通过示例加深理解
定义 两个环绕增强,对目标类进行增强
- 定义环绕增强, 即定义Advice对象。 MethodInterceptor是Advice的子类
public class AroundAdvise implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before");
Object retVal = invocation.proceed();
System.out.println("after");
return retVal;
}
}
另一个环绕增强
public class AnotherAroundAdvise implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println(" another before");
Object retVal = invocation.proceed();
System.out.println(" another after");
return retVal;
}
}
- 定义目标类,即被增强对象
public class NameMatchMethodTargetBean {
public void run() {
System.out.println("--- NameMatchMethodTargetBean running ---");
}
}
- 定义pointcut 并组合增强点,后创建代理对象
// 定义根据名称匹配的pointcut
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
// 指定匹配名称为run的方法
pointcut.addMethodName("run");
// 目标代理对象
NameMatchMethodTargetBean targetBean = new NameMatchMethodTargetBean();
// 增强点
Advice advice = new AroundAdvise();
Advice another = new AnotherAroundAdvise();
// 组合切入点合增强点
Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
Advisor anotherAdvisor = new DefaultPointcutAdvisor(pointcut, another);
// 生成代理对象
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.addAdvisor(advisor);
proxyFactory.addAdvisor(anotherAdvisor);
proxyFactory.setTarget(targetBean);
NameMatchMethodTargetBean proxyBean = (NameMatchMethodTargetBean) proxyFactory.getProxy();
proxyBean.run();
得到的结果
before
another before
--- NameMatchMethodTargetBean running ---
another after
after
从以上示例可以看出, 切入点合增强点是独立的,可以组合在一起。 增强点加入ProxyFactory后由list维护,list的顺序决定了advice的触发顺序.
流式切入点
流式切入点的功能是,指定从特定的类方法的调用才触发增强,其他方式调用不会触发。
- 切入点使用上一个示例的代码
- 目标类也使用上一个示例的代码,并添加多一个方法
public void run() {
System.out.println(" target bean is running ");
}
- 定义流式切入点,并触发
public class StartUp {public static void main(String[] args) {
TargetBean targetBean = new TargetBean();
// 定义切入点pointcut
Pointcut pc = new ControlFlowPointcut(StartUp.class, "runFun");
// 增强点
Advice advice = new SimpleAdvise();
// 组合切入点和增强点
Advisor advisor = new DefaultPointcutAdvisor(pc, advice);
// 创建代理
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.addAdvisor(advisor);
proxyFactory.setTarget(targetBean);
TargetBean proxy = (TargetBean) proxyFactory.getProxy();
// 直接调用
proxy.run();
System.out.println("--------------------");
// 控制流式调用
runFun(proxy);
}public static void runFun(TargetBean targetBean) {
targetBean.run();
}
}
运行结果
target bean is running
--------------------
before
target bean is running
after
可以看到,直接调用代理对象的方法是不会触发增强点,需要通过流式切入点声明的对象方法才能触发增强.
引入增强示例
- 定义需要引入的功能, 这里定义一个接口,使目标类由该接口的功能
public interface IntroductionInterface {
void doSomething();
}
- 定义引入增强
/**
* 引入增强, 使被增强者 实现了 IntroductionInterface接口
*/
public class IntroductionAdvise extends DelegatingIntroductionInterceptor implements IntroductionInterface {
@Override
public void doSomething() {
System.out.println("你已被我增强!");
}
}
这样就定义完成了, 这里对上一个示例的目标类NameMatchMethodTargetBean进行增强
// 引入增强
Advice introductionAdvice = new IntroductionAdvise();
// 引入增强不能和pointcut使用
Advisor introductionAdvisor = new DefaultIntroductionAdvisor(introductionAdvice);
// 生成代理对象,代理对象即是targetBean也是IntroductionInterface
ProxyFactory newProxyFactory = new ProxyFactory();
newProxyFactory.addAdvisor(introductionAdvisor);
newProxyFactory.setTarget(targetBean);
Object newProxyBean = newProxyFactory.getProxy();
if (newProxyBean instanceof IntroductionInterface) {
((IntroductionInterface) newProxyBean).doSomething();
}
以上即完成了对目标类NameMatchMethodTargetBean 引入了IntroductionInterface
ProxyFactoryBean
请看 https://www.jianshu.com/p/857c8cdf99c6
ProxyFactory
请看文字开头的示例
auto-proxy 自动开启代理
请看https://www.jianshu.com/p/b2f3f3058652
TargetSource
指的是被代理原始对象, spring中代理对象触发方法最终都会请求原始对象方法.
通常情况下不用关心原始对象. 不过可以通过这个特性实现特殊效果
对象池: 因为每次都会触发原始对象,那么就可以每次触发返回的原始对象都不一样。
热更新: 在线更新掉原始对象。
自定义增强类型
总结 aop是一种编程理念,spring的aop由自己规定的名词,也有aop联盟的规范。
只有了解定义名词的用途和边界,才能对aop做进一步的理解。
https://www.jianshu.com/p/b2f3f3058652
推荐阅读
- 由浅入深理解AOP
- Activiti(一)SpringBoot2集成Activiti6
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- Python基础|Python基础 - 练习1
- 2018-07-09|2018-07-09 Spring 的DBCP,c3p0
- Java|Java基础——数组
- Java基础-高级特性-枚举实现状态机
- 营养基础学20180331(课间随笔)??
- iOS面试题--基础