一、AOP的关键概念
AOP:Aspect Oriented Programming的缩写,意为:面向切面编程。
- Joinpoint(连接点):程序执行中的候选者点, 例如一个被调用的方法, 或者是一个异常的处理; 简单来讲和方法有关的前前后后都是连接点。
- Pointcut(切点):如果连接点相当于数据中的记录,那么切点相当于查询条件,一个切点可以匹配多个连接点。所以切点表示一组Joinpoint,这些Jointpoint或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。
- Advice(通知/增强):通知是织入到目标类连接点上的一段程序代码,包含增强的横切代码。
- Advisor(顾问/增强器):Advisor是切面的另一种实现,绑定通知跟切点,增强器中包含通知和切点属性。
- Introduction(引介):引介是一种特殊的通知,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过引介功能,可以动态的为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。
- Interceptor(拦截器):在Advice的基础上扩展定义,定义了通知的增强方式,也就是通过对Joinpoint(连接点)的拦截。一个通用的拦截器可以拦截发生在基础程序中的运行时事件。
- Aspect(切面): 切面是由Pointcut(切点)和Advice(通知)组成的,它包括了对横切关注功能的定义,也包括了对连接点的定义。
- TargetSource(目标对象):包含连接点的对象。也被称作被通知或被代理对象。
- Proxy(代理对象):包含了原始对象的代码(是在合适的位置调用目标对象的方法)和增加后的代码(Advice通知的内容)的那个对象。
- Weaving(织入):织入是将Advice通知添加到目标类具体连接点上的过程,AOP有三种织入方式:①编译期织入:需要特殊的Java编译期(例如AspectJ的ajc);②装载期织入:要求使用特殊的类加载器,在装载类的时候对类进行增强;③运行时织入:在运行时为目标类生成代理实现增强。AspectJ采用了编译期织入和装载期织入的方式,Spring采用了动态代理的方式实现了运行时织入。
二、Advice(通知、增强)
// Advice是一个标记接口
public interface Advice {
}
// 拦截器也是一个Advice接口,是一个标记接口
public interface Interceptor extends Advice {
}
// BeforeAdvice 也是一个标记接口
public interface BeforeAdvice extends Advice {
}
public interface MethodBeforeAdvice extends BeforeAdvice {
/**
* Callback before a given method is invoked.
* @param method method being invoked
* @param args arguments to the method
* @param target target of the method invocation. May be {@code null}.
* @throws Throwable if this object wishes to abort the call.
* Any exception thrown will be returned to the caller if it's
* allowed by the method signature. Otherwise the exception
* will be wrapped as a runtime exception.
*/
void before(Method method, Object[] args, @Nullable Object target) throws Throwable;
}
// AfterAdvice 也是一个标记接口
public interface AfterAdvice extends Advice {
}
// ThrowsAdvice 也是一个标记接口
public interface ThrowsAdvice extends AfterAdvice {
}
public interface AfterReturningAdvice extends AfterAdvice {
/**
* Callback after a given method successfully returned.
* @param returnValue the value returned by the method, if any
* @param method method being invoked
* @param args arguments to the method
* @param target target of the method invocation. May be {@code null}.
* @throws Throwable if this object wishes to abort the call.
* Any exception thrown will be returned to the caller if it's
* allowed by the method signature. Otherwise the exception
* will be wrapped as a runtime exception.
*/
void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;
}
Advice有以下几种常见的类型:
- AspectJMethodBeforeAdvice:前置通知。AspectJ中 before 属性对应的通知(@Before标注的方法会被解析成该通知),在切面方法执行之前执行。
- AspectJAfterReturningAdvice:后置通知。AspectJ中 afterReturning 属性对应的通知(@AfterReturning 标注的方法会被解析成该通知),在切面方法执行之后执行,如果有异常,则不执行。注意:该通知与AspectJMethodBeforeAdvice对应。
- AspectJAroundAdvice:环绕通知。AspectJ中 around 属性对应的通知(@Around标注的方法会被解析成该通知),在切面方法执行前后执行。
- AspectJAfterAdvice:返回通知。AspectJ中 after 属性对应的通知(@After 标注的方法会被解析成该通知),不论是否异常都会执行。
- AspectJAfterThrowingAdvice:异常通知,AspectJ中 after 属性对应的通知(@AfterThrowing标注的方法会被解析成该通知),在连接点抛出异常后执行。
Advice是一个标记接口,所有的advice都直接或者间接继承了interceptor(拦截器)接口,也就是说,所有的通知实际上就是拦截器。
通知的执行顺序为: around->before->方法本身->around->after->afterReturning
三、 Advisor(顾问/增强器)
Advisor是切面的另一种实现,绑定通知跟切点,包含advice和pointcut属性。
public interface Advisor {
Advice EMPTY_ADVICE = new Advice() {};
Advice getAdvice();
boolean isPerInstance();
}
public interface PointcutAdvisor extends Advisor {
Pointcut getPointcut();
}
InstantiationModelAwarePointcutAdvisorImpl:springboot自动装配的顾问类型。是最常用的一种顾问实现。在注解实现的切面中,所有@Aspect类,都会被解析成该对象。
四、 Pointcut(切点)
public interface Pointcut {
ClassFilter getClassFilter(); //获取类过滤器
MethodMatcher getMethodMatcher(); // 获取方法匹配器
Pointcut TRUE = TruePointcut.INSTANCE;
}
public interface ClassFilter {
// 指定的类是否匹配
boolean matches(Class<?> clazz);
ClassFilter TRUE = TrueClassFilter.INSTANCE;
}
public interface MethodMatcher {
boolean matches(Method method, Class<?> targetClass); // 测试此切入点是否与目标类上的给定方法匹配,当创建AOP代理时可以执行此评估,以避免对每个方法调用进行测试
boolean isRuntime(); //如果返回true,则在每次方法调用时都会调下面的用三个参数匹配的方法,这允许切入点在执行目标通知之前查看传递给方法调用的参数
boolean matches(Method method, Class<?> targetClass, Object... args);
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}
- AnnotationMatchingPointcut:注解匹配切点。根据类上或方法上是否存在指定的注解判断切点的匹配性,如果没有显示指定注解,则匹配所有。
- DynamicMethodMatcherPointcut:动态方法匹配器切点。它本质上是一个方法匹配器,但同时具有了切点的功能。
- ComposablePointcut:可组合的切点。这种切点可以与或逻辑,任意组合其他的Pointcut、ClassFilter和MethodMatcher。其本质是通过ClassFilters和MethodMatchers两个工具类进行Pointcut内部组件的组合。
- JdkRegexpMethodPointcut: JDK正则表达式切点,即使用正则表达式描述方法的拦截规则和排除规则。
- AspectJExpressionPointcut:AspectJ切点表达式切点。顾名思义,使用AspectJ的切点表达式描述筛选规则。表达式基本语法如下(非完整语法):execution(<方法修饰符>? <方法返回值类型> <包名>.<类名>.<方法名>(<参数类型>) [throws <异常类型>]?); 其中,‘*’代表0个或多个任意字符,包名中的..(两个点)代表当前包及其子包,参数列表中的..代表任意个参数。如:execution(public static * *..*.*(..) throws *),此表达式匹配所有方法。
五、TargetSource(目标对象)
public interface TargetSource extends TargetClassAware {
/**
* Return the type of targets returned by this {@link TargetSource}.
* <p>Can return {@code null}, although certain usages of a {@code TargetSource}
* might just work with a predetermined target class.
* @return the type of targets returned by this {@link TargetSource}
*/
@Override
@Nullable
Class<?> getTargetClass();
/**
* Will all calls to {@link #getTarget()} return the same object?
* <p>In that case, there will be no need to invoke {@link #releaseTarget(Object)},
* and the AOP framework can cache the return value of {@link #getTarget()}.
* @return {@code true} if the target is immutable
* @see #getTarget
*/
boolean isStatic();
/**
* Return a target instance. Invoked immediately before the
* AOP framework calls the "target" of an AOP method invocation.
* @return the target object which contains the joinpoint,
* or {@code null} if there is no actual target instance
* @throws Exception if the target object can't be resolved
*/
@Nullable
Object getTarget() throws Exception;
/**
* Release the given target object obtained from the
* {@link #getTarget()} method, if any.
* @param target object obtained from a call to {@link #getTarget()}
* @throws Exception if the object can't be released
*/
void releaseTarget(Object target) throws Exception;
}
TargetSource被用于获取当前MethodInvocation(方法调用)所需要的target(目标对象),这个target通过反射的方式被调用(如:method.invode(target,args))。换句话说,proxy(代理对象)代理的不是target,而是TargetSource。
4个简单实现包括:
(1)EmptyTargetSource:静态目标源,当不存在target目标对象,或者甚至连targetClass目标类都不存在(或未知)时,使用此类实例。
(2)HotSwappableTargetSource:动态目标源,支持热替换的目标源,支持spring应用运行时替换目标对象。
(3)JndiObjectTargetSource:spring对JNDI管理bean的支持,static属性可配置。
(4)SingletonTargetSource:静态目标源,单例目标源。Spring的AOP框架默认为受IoC容器管理的bean创建此目标源。换句话说,SingletonTargetSource、proxy与目标bean三者的声明周期均相同。如果bean被配置为prototype,则spring会在每次getBean时创建新的SingletonTargetSource实例。
3大类实现包括:
(1)AbstractBeanFactoryBasedTargetSource:此类目标源基于IoC容器实现,也就是说target目标对象可以通过beanName从容器中获取。此类又扩展出:① SimpleBeanTargetSource:简单实现,直接调用getBean从容器获取目标对象;② LazyInitTargetSource:延迟初始化目标源,子类可重写postProcessTargetObject方法后置处理目标对象;③AbstractPrototypeBasedTargetSource:原型bean目标源,此抽象类可确保beanName对应的bean的scope属性为prototype。其子类做了简单原型、池化原型、线程隔离原型这3种实现。
(2)AbstractRefreshableTargetSource:可刷新的目标源。此类实现可根据配置的刷新延迟时间,在每次获取目标对象时自动刷新目标对象。
(3)AbstractLazyCreationTargetSource:此类实现在调用getTarget()获取时才创建目标对象
六 、示例
前置准备代码:
@Data
@AllArgsConstructor
public class Book {
private String name;
}
// 接口定义
public interface BookService {
Book create(String name);
Book query(String name);
}
@Component
public class BookServiceImp implements BookService{
@Override
public Book create(String name) {
System.out.println("BookServiceImp.create called");
return new Book(name);
}
@Override
public Book query(String name) {
System.out.println("BookServiceImp.query called");
return new Book(name);
}
}
@Component
public class LogBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("准备执行方法:" + method.getName() + ", 参数列表:" + Arrays.toString(args));
}
}
@Component
public class LogAfterReturningAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("方法返回:" + returnValue);
}
}
3.1 ProxyFactoryBean 注入bean工厂
ProxyFactoryBean是一个代理工厂,指定目标对象,代理接口和拦截器/增强器后,可以生产指定代理对象的代理工厂的bean(不修改原有的bean)。ProxyConfig中主要封装了代理的通用处理逻辑,比如设置目标类,设置使用cglib还是java proxy等一些基础配置
3.1.1 直接设置拦截器实现类级别的拦截
ProxyFactoryBean设置拦截器,实现类级别的拦截:
@SpringBootApplication
public class Springboot001Application {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(Springboot001Application.class, args);
//未代理对象
BookService bookService = (BookService)run.getBean("bookServiceImp");
bookService.create("小白学习aop:原始bean");
// 代理对象
bookService = (BookService)run.getBean("bookServiceProxy");
bookService.create("小白学习aop:代理bean");
}
@Bean
public ProxyFactoryBean bookServiceProxy() throws ClassNotFoundException {
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
// 设置拦截器的bean名称(advice通知)
proxyFactoryBean.setInterceptorNames("logBeforeAdvice", "logAfterReturningAdvice");
// 设置代理的接口
proxyFactoryBean.setProxyInterfaces(new Class[]{BookService.class});
// 设置目标对象
proxyFactoryBean.setTargetName("bookServiceImp");
return proxyFactoryBean;
}
}
执行结果:
3.1.2 设置增强器实现方法级别的拦截
ProxyFactoryBean设置增强器,实现类方法级别的拦截(以NameMatchMethodPointcutAdvisor 为例,匹配方法名称):
@SpringBootApplication
public class Springboot001Application {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(Springboot001Application.class, args);
//未代理对象
BookService bookService = (BookService)run.getBean("bookServiceImp");
bookService.create("小白学习aop:原始bean");
// 代理对象
bookService = (BookService)run.getBean("bookServiceProxy");
bookService.create("小白学习aop:代理bean");
}
@Bean
public NameMatchMethodPointcutAdvisor bookServiceBeforeAdvisor(Advice logBeforeAdvice) {
NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor(logBeforeAdvice);
advisor.setMappedName("create"); // 匹配create方法
return advisor;
}
@Bean
public NameMatchMethodPointcutAdvisor bookServiceAfterReturnAdvisor(Advice logAfterReturningAdvice) {
NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor(logAfterReturningAdvice);
advisor.setMappedName("create"); // 匹配create方法
return advisor;
}
@Bean
public ProxyFactoryBean bookServiceProxy() throws ClassNotFoundException {
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
// 使用增强器设置拦截器
proxyFactoryBean.setInterceptorNames("bookServiceBeforeAdvisor", "bookServiceAfterReturnAdvisor");
// 设置代理的接口
proxyFactoryBean.setProxyInterfaces(new Class[]{BookService.class});
// 设置目标对象
proxyFactoryBean.setTargetName("bookServiceImp");
return proxyFactoryBean;
}
执行结果:
3.1.3 ProxyFactoryBean源码分析
ProxyFactoryBean实现了FactoryBean接口,是一个工厂bean,实现了getObject方法:
public Object getObject() throws BeansException {
initializeAdvisorChain(); //初始化增强器链
if (isSingleton()) {
return getSingletonInstance(); // 获取单例对象
}
else {
if (this.targetName == null) {
logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
// 判断是否已经初始化过
if (this.advisorChainInitialized) {
return;
}
if (!ObjectUtils.isEmpty(this.interceptorNames)) {
// ... 省略部分代码
// 获取所有的拦截器bean名称,并从bean工厂中获取拦截器实例,加入增强器链
for (String name : this.interceptorNames) {
// ... 省略部分代码
Object advice;
if (this.singleton || this.beanFactory.isSingleton(name)) {
advice = this.beanFactory.getBean(name);
}
else {
advice = new PrototypePlaceholderAdvisor(name);
}
// 将通知加入增强器链
addAdvisorOnChainCreation(advice);
}
}
this.advisorChainInitialized = true; // 设置已经初始化
}
private void addAdvisorOnChainCreation(Object next) {
// namedBeanToAdvisor将bean对象转换为增强器对象
addAdvisor(namedBeanToAdvisor(next));
}
private Advisor namedBeanToAdvisor(Object next) {
// ... 省略部分代码,advisorAdapterRegistry未设置时默认为DefaultAdvisorAdapterRegistry
return this.advisorAdapterRegistry.wrap(next);
}
// 获取单例对象
private synchronized Object getSingletonInstance() {
// singletonInstance为代理对象,如果为空,则创建代理对象
if (this.singletonInstance == null) {
// ... 省略部分代码
super.setFrozen(this.freezeProxy);
// createAopProxy 创建AOP代理,getProxy通过代理获取代理对象
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}
// 创建AOP代理
protected final synchronized AopProxy createAopProxy() {
// ... 省略部分代码,aop代理工厂默认为DefaultAopProxyFactory
// 创建代理对象时,入参为this,也就是创建ProxyFactoryBean对象的代理对象
return getAopProxyFactory().createAopProxy(this);
}
// 获取代理对象,如果aopProxy代理是JdkDynamicAopProxy类型,使用JDK动态代理创建代理对象
protected Object getProxy(AopProxy aopProxy) {
return aopProxy.getProxy(this.proxyClassLoader);
}
// 默认增强器转换适配器
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter()); // 前置通知适配器
registerAdvisorAdapter(new AfterReturningAdviceAdapter()); // 返回通知适配器
registerAdvisorAdapter(new ThrowsAdviceAdapter()); // 异常通知适配器
}
@Override
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
// 如果传入对象已经是增强器,直接返回(3.1.2直接使用增强器作为拦截器)
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
// 方法拦截器,直接封装为DefaultPointcutAdvisor,增强器中的切点为匹配所有
if (advice instanceof MethodInterceptor) {
return new DefaultPointcutAdvisor(advice);
}
// 根据支持的适配器转换
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
@Override
public void registerAdvisorAdapter(AdvisorAdapter adapter) {
this.adapters.add(adapter);
}
}
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (!NativeDetector.inNativeImage() &&
(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
Class<?> targetClass = config.getTargetClass();
// ... 省略部分代码
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config); //JDK的动态AOP代理
}
return new ObjenesisCglibAopProxy(config); // CGLIB的动态代理
}
else {
return new JdkDynamicAopProxy(config);
}
}
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
}
3.1.4 JdkDynamicAopProxy 执行
使用JDK动态代理时, 执行bookService.create("小白学习aop:代理bean")时,实际执行的时JdkDynamicAopProxy的invoke方法:
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
// .. 省略部分代码
private final AdvisedSupport advised; // 存储的是ProxyFactoryBean对象
private final Class<?>[] proxiedInterfaces; // 代理的接口
@Override
// 获取代理对象
public Object getProxy() {
return getProxy(ClassUtils.getDefaultClassLoader());
}
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// ..省略部分代码,只有代理的接口方法才走下面的方法
Object retVal;
// .. 省略部分代码
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 获得拦截器链,先查看方法对应的缓存是否有拦截器链,如果没有,通过增强器链工厂和method、adviece链表生成拦截器链,并存储方法对应的缓存
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 根据拦截器链和目标类、调用方法进行反射调用
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
// 省略部分代码
}
// .. 省略部分代码
}
3.2 BeanNameAutoProxyCreator 指定拦截器和需要AOP代理的bean进行自动代理
BeanNameAutoProxyCreator可以指定拦截器(通知/增强器)以及需要进行代理的bean名称,对bean自动生成代理对象。BeanNameAutoProxyCreator继承了BeanPostProcessor接口,在bean后置处理器中,如果发现自己需要进行AOP代理,则从指定的通知/增强器中,查找能用于当前类的通知/增强器,生成代理对象,取代目标对象。
public class Springboot001Application {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(Springboot001Application.class, args);
// bookService已经是代理对象
BookService bookService = (BookService)run.getBean("bookServiceImp");
bookService.create("小白学习aop:原始bean");
}
@Bean
public NameMatchMethodPointcutAdvisor bookServiceBeforeAdvisor(Advice logBeforeAdvice) {
NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor(logBeforeAdvice);
advisor.setMappedName("create"); // 匹配create方法
return advisor;
}
@Bean
public NameMatchMethodPointcutAdvisor bookServiceAfterReturnAdvisor(Advice logAfterReturningAdvice) {
NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor(logAfterReturningAdvice);
advisor.setMappedName("create"); // 匹配create方法
return advisor;
}
@Bean
public BeanNameAutoProxyCreator bookServiceProxy() {
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
// 使用增强器作为拦截器
beanNameAutoProxyCreator.setInterceptorNames("bookServiceBeforeAdvisor", "bookServiceAfterReturnAdvisor");
// 设置需要生成AOP代理的bean name,可以使用通配符*
beanNameAutoProxyCreator.setBeanNames("*ServiceImp");
return beanNameAutoProxyCreator;
}
}
执行结果:
3.3 DefaultAdvisorAutoProxyCreator
DefaultAdvisorAutoProxyCreator比BeanNameAutoProxyCreator,会对所有的bean查看是否需要生成AOP代理对象。在bean后置处理器中,查询到bean工厂中所有的增强器,如果有能用于当前类的AOP代理对象(PointCut能匹配当前类或者类中的某些方法),则使用这些增强器生成代理对象。
@SpringBootApplication
public class Springboot001Application {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(Springboot001Application.class, args);
// bookService已经是代理对象
BookService bookService = (BookService)run.getBean("bookServiceImp");
bookService.create("小白学习aop:原始bean");
}
@Bean
public NameMatchMethodPointcutAdvisor bookServiceBeforeAdvisor(Advice logBeforeAdvice) {
NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor(logBeforeAdvice);
advisor.setMappedName("create"); // 匹配create方法
return advisor;
}
@Bean
public NameMatchMethodPointcutAdvisor bookServiceAfterReturnAdvisor(Advice logAfterReturningAdvice) {
NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor(logAfterReturningAdvice);
advisor.setMappedName("create"); // 匹配create方法
return advisor;
}
@Bean
public DefaultAdvisorAutoProxyCreator bookServiceProxy() {
return new DefaultAdvisorAutoProxyCreator();
}
}
4、通过注解开发
@EnableAspectJAutoProxy开启AOP,注解中improt AspectJAutoProxyRegistrar。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
AspectJAutoProxyRegistrar中注册了AnnotationAwareAspectJAutoProxyCreator bean,改aop自动代理创建器的执行过程和DefaultAdvisorAutoProxyCreator类似,在bean的后置处理器处理过程中,查找可用的advisors并生成代理对象。在查找可用的advisor时,会查找Aspect注解的切面类并创建增强器advisor对象。
@Override
// 注入beanFactory时执行(实现BeanFactoryAware接口)
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
if (this.aspectJAdvisorFactory == null) {
// 设置增强器生成工厂
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
}
// 设置增强器构建适配器
this.aspectJAdvisorsBuilder =
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}
@Override
// 查找候选advisors
protected List<Advisor> findCandidateAdvisors() {
List<Advisor> advisors = super.findCandidateAdvisors();
if (this.aspectJAdvisorsBuilder != null) {
// buildAspectJAdvisors会查找所有注解创建的advisors(解析含有Aspect注解的bean定义)
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
参考文章:https://www.cnblogs.com/xxkj/p/14094203.html
spring 5参考指南:https://docs.flydean.com/spring-framework-documentation5/