手写Spring:第13章-把AOP扩展到Bean的生命周期

文章目录

  • 一、目标:把AOP扩展到Bean的生命周期
  • 二、设计:把AOP扩展到Bean的生命周期
  • 三、实现:把AOP扩展到Bean的生命周期
    • [3.1 工程结构](#3.1 工程结构)
    • [3.2 AOP动态代理融入Bean的生命周期类图](#3.2 AOP动态代理融入Bean的生命周期类图)
    • [3.3 定义Advice拦截器链](#3.3 定义Advice拦截器链)
      • [3.3.1 定义拦截器链接口](#3.3.1 定义拦截器链接口)
      • [3.3.2 方法拦截器链接口](#3.3.2 方法拦截器链接口)
    • [3.4 定义Advisor访问者](#3.4 定义Advisor访问者)
      • [3.4.1 定义拦截器访问者接口](#3.4.1 定义拦截器访问者接口)
      • [3.4.2 定义切面拦截器访问者](#3.4.2 定义切面拦截器访问者)
      • [3.4.3 切面访问者实现类](#3.4.3 切面访问者实现类)
      • [3.4.4 方法拦截器](#3.4.4 方法拦截器)
    • [3.5 代理工厂](#3.5 代理工厂)
      • [3.5.1 切面添加代理配置](#3.5.1 切面添加代理配置)
      • [3.5.2 定义代理工厂](#3.5.2 定义代理工厂)
    • [3.6 融入Bean生命周期的自动代理创建者](#3.6 融入Bean生命周期的自动代理创建者)
      • [3.6.1 实例化感知对象处理](#3.6.1 实例化感知对象处理)
      • [3.6.2 默认自动代理创建者](#3.6.2 默认自动代理创建者)
    • [3.7 融入到Bean的生命周期](#3.7 融入到Bean的生命周期)
  • 四、测试:把AOP扩展到Bean的生命周期
    • [4.1 添加测试配置](#4.1 添加测试配置)
      • [4.1.1 用户自定义拦截方法](#4.1.1 用户自定义拦截方法)
      • [4.1.2 配置文件](#4.1.2 配置文件)
    • [4.2 单元测试](#4.2 单元测试)
      • [4.2.0 测试环境初始化](#4.2.0 测试环境初始化)
      • [4.2.1 前置拦截器测试](#4.2.1 前置拦截器测试)
      • [4.2.2 拦截器访问者测试](#4.2.2 拦截器访问者测试)
      • [4.2.3 单元测试](#4.2.3 单元测试)
  • 五、总结:把AOP扩展到Bean的生命周期

一、目标:把AOP扩展到Bean的生命周期

💡 如何完成AOP和Spring框架的整合?

  • 现在通过基于 Proxy.newProxyInstance 代理操作中处理方法匹配和方法拦截,对匹配的对象进行自定义的处理操作。
  • 并把这样的技术核心内容拆解到 Spring 中,用于实现 AOP 部分,通过拆分后基本可以明确各个类的职责,包括你的代理目标对象属性、拦截器属性、方法匹配属性,以及两种不同的代理操作 JDKCglib 的方式。
  • 在有了一个 AOP 核心功能的实现后,我们通过单元测试的方式进行验证切面功能对方法进行拦截,但如果这是一个面向用户使用的功能,就不太可能让用户这么复杂且没有与 Spring 结合的方式单独使用 AOP
  • 因此我们需要完成 AOP 核心功能和 Spring 框架的整合,最终能通过在 Spring 配置的方式完成切面的操作。

二、设计:把AOP扩展到Bean的生命周期

💡 怎么借着 BeanPostProcessor 把动态代理融入到 Bean 的生命周期中,以及如何组装各项切点、拦截、前置的功能和适配对应的代理器?

  • 为了可以让对象创建过程中,能把 xml 中配置的代理对象(切面)的一些类对象实例化,就需要用到 BeanPostProcessor 提供的方法。
    • 因为这个类中的方法可以分别作用与 Bean 对象执行初始化前后修改 Bean 的对象的扩展信息。
    • 但这里需要于 BeanPostProcessor 实现新的接口和实现类,这样才能定向获取对应的类信息。
  • 因为创建的代理对象不是流程里的普通对象,所以需要前置于其他对象的创建。
    • 实际开发中,需要在 AbstractAutowireCapableBeanFactory#createBean 优先完成 Bean 对象的判断,是否需要代理,有则直接返回代理对象。
  • 还需要解决方法拦截器的具体功能,提供一些 BeforeAdvice、AfterAdvice 的实现,让用户可以更简化的使用切面对象。
  • 除此以外还包括:需要包装切面表达式以及拦截方法的整合、提供不同类型的代理方式的代理工厂,来包装切面服务。

三、实现:把AOP扩展到Bean的生命周期

3.1 工程结构

java 复制代码
spring-step-12
|-src
	|-main
	|	|-java
	|		|-com.lino.springframework
	|			|-aop
	|			|	|-aspectj
	|			|	|	|-AspectJExpressionPointcut.java
	|			|	|	|-AspectJExpressionPointcutAdvisor.java
	|			|	|-framework
	|			|	|	|-adapter
	|			|	|	|	|-MethodBeforeAdviceInterceptor.java
	|			|	|	|-autoproxy
	|			|	|	|	|-DefaultAdvisorAutoProxyCreator.java
	|			|	|	|-AopProxy.java
	|			|	|	|-Cglib2AopProxy.java
	|			|	|	|-JdkDynamicAopProxy.java
	|			|	|	|-ProxyFactory.java
	|			|	|	|-ReflectiveMethodInvocation.java
	|			|	|-AdvisedSupport.java
	|			|	|-Advisor.java
	|			|	|-BeforeAdvice.java
	|			|	|-ClassFilter.java
	|			|	|-MethodBeforeAdvice.java
	|			|	|-MethodMatcher.java
	|			|	|-Pointcut.java
	|			|	|-PointcutAdvisor.java
	|			|	|-TargetSource.java
	|			|-beans
	|			|	|-factory
	|			|	|	|-config
	|			|	|	|	|-AutowireCapableBeanFactory.java
	|			|	|	|	|-BeanDefinition.java
	|			|	|	|	|-BeanFactoryPostProcessor.java
	|			|	|	|	|-BeanPostProcessor.java
	|			|	|	|	|-BeanReference.java
	|			|	|	|	|-ConfigurableBeanFactory.java
	|			|	|	|	|-InstantiationAwareBeanPostProcessor.java
	|			|	|	|	|-SingletonBeanRegistry.java
	|			|	|	|-support
	|			|	|	|	|-AbstractAutowireCapableBeanFactory.java
	|			|	|	|	|-AbstractBeabDefinitionReader.java
	|			|	|	|	|-AbstractBeabFactory.java
	|			|	|	|	|-BeabDefinitionReader.java
	|			|	|	|	|-BeanDefinitionRegistry.java
	|			|	|	|	|-CglibSubclassingInstantiationStrategy.java
	|			|	|	|	|-DefaultListableBeanFactory.java
	|			|	|	|	|-DefaultSingletonBeanRegistry.java
	|			|	|	|	|-DisposableBeanAdapter.java
	|			|	|	|	|-FactoryBeanRegistrySupport.java
	|			|	|	|	|-InstantiationStrategy.java
	|			|	|	|	|-SimpleInstantiationStrategy.java
	|			|	|	|-xml
	|			|	|	|	|-XMLBeanDefinitionReader.java
	|			|	|	|-Aware.java
	|			|	|	|-BeanClassLoaderAware.java
	|			|	|	|-BeanFactory.java
	|			|	|	|-BeanFactoryAware.java
	|			|	|	|-BeanNameAware.java
	|			|	|	|-ConfigurableListableBeanFactory.java
	|			|	|	|-DisposableBean.java
	|			|	|	|-FactoryBean.java
	|			|	|	|-HierarcgicalBeanFactory.java
	|			|	|	|-InitializingBean.java
	|			|	|	|-ListableBeanFactory.java
	|			|	|-BeansException.java
	|			|	|-PropertyValue.java
	|			|	|-PropertyValues.java
	|			|-context
	|			|	|-event
	|			|	|	|-AbstractApplicationEventMulticaster.java
	|			|	|	|-ApplicationContextEvent.java
	|			|	|	|-ApplicationEventMulticaster.java
	|			|	|	|-ContextclosedEvent.java
	|			|	|	|-ContextRefreshedEvent.java
	|			|	|	|-SimpleApplicationEventMulticaster.java
	|			|	|-support
	|			|	|	|-AbstractApplicationContext.java
	|			|	|	|-AbstractRefreshableApplicationContext.java
	|			|	|	|-AbstractXmlApplicationContext.java
	|			|	|	|-ApplicationContextAwareProcessor.java
	|			|	|	|-ClassPathXmlApplicationContext.java
	|			|	|-ApplicationContext.java
	|			|	|-ApplicationContextAware.java
	|			|	|-ApplicationEvent.java
	|			|	|-ApplicationEventPublisher.java
	|			|	|-ApplicationListener.java
	|			|	|-ConfigurableApplicationContext.java
	|			|-core.io
	|			|	|-ClassPathResource.java
	|			|	|-DefaultResourceLoader.java
	|			|	|-FileSystemResource.java
	|			|	|-Resource.java
	|			|	|-ResourceLoader.java
	|			|	|-UrlResource.java
	|			|-util
	|			|	|-ClassUtils.java
	|-test
		|-java
			|-com.lino.springframework.test
                |-bean
                |	|-IUserService.java
                |	|-UserService.java
                |	|-UserServiceBeforeAdvice.java
                |	|-UserServiceInterceptor.java
                |-ApiTest.java
		|-resources
			|-spring.xml

3.2 AOP动态代理融入Bean的生命周期类图

  • 整个类图看,在以 BeanPostProcessor 接口实现继承的 InstantiationAwareBeanPostProcessor 接口后,做了一个自动代理创建的类 DefaultAdvisorAutoProxyCreator,这个类就是用于处理整个 AOP 代理融入到 Bean 生命周期中的核心类。
  • DefaultAdvisorAutoProxyCreator 会依赖于拦截器、代理工厂和 PointcutAdvisor 的包装服务 AspectJExpressionPointcutAdvisor,由它提供切面、拦截方法和表达式。
  • Spring AOPAdvice 细化了 BeforeAdviceAfterAdviceAfterReturningAdviceThrowsAdvice

3.3 定义Advice拦截器链

3.3.1 定义拦截器链接口

BeforeAdvice.java

java 复制代码
package com.lino.springframework.aop;

import org.aopalliance.aop.Advice;

/**
 * @description: 拦截器链
 */
public interface BeforeAdvice extends Advice {
}

3.3.2 方法拦截器链接口

MethodBeforeAdvice.java

java 复制代码
package com.lino.springframework.aop;

import java.lang.reflect.Method;

/**
 * @description: 方法拦截器链
 */
public interface MethodBeforeAdvice extends BeforeAdvice {

    /**
     * 方法执行之前拦截
     *
     * @param method 方法
     * @param args   方法参数
     * @param target 目标对象
     * @throws Throwable 异常
     */
    void before(Method method, Object[] args, Object target) throws Throwable;
}
  • Spring 框架中,Advice 都是通过方法拦截器 MethodInterceptor 实现的。环绕 Advice 类似一个拦截器的链路,Before Advice、After Advice 等。

3.4 定义Advisor访问者

3.4.1 定义拦截器访问者接口

Advisor.java

java 复制代码
package com.lino.springframework.aop;

import org.aopalliance.aop.Advice;

/**
 * @description: 拦截器访问者
 */
public interface Advisor {

    /**
     * 获取拦截器
     *
     * @return 拦截器
     */
    Advice getAdvice();
}

3.4.2 定义切面拦截器访问者

PointcutAdvisor.java

java 复制代码
package com.lino.springframework.aop;

/**
 * @description: 切面拦截器访问者
 */
public interface PointcutAdvisor extends Advisor {

    /**
     * 获取切面
     *
     * @return 切面
     */
    Pointcut getPointcut();
}
  • PointcutAdvisor 承担了 PointcutAdvice 的组合。
    • Pointcut:用于获取 JoinPoint
    • Advice:决定 JoinPoint 执行什么操作。

3.4.3 切面访问者实现类

AspectJExpressionPointcutAdvisor.java

java 复制代码
package com.lino.springframework.aop.aspectj;

import com.lino.springframework.aop.Pointcut;
import com.lino.springframework.aop.PointcutAdvisor;
import org.aopalliance.aop.Advice;

/**
 * @description: 切面访问者实现类
 */
public class AspectJExpressionPointcutAdvisor implements PointcutAdvisor {

    /**
     * 切面
     */
    private AspectJExpressionPointcut pointcut;
    /**
     * 具体拦截方法
     */
    private Advice advice;
    /**
     * 表达式
     */
    private String expression;

    public void setExpression(String expression) {
        this.expression = expression;
    }

    @Override
    public Pointcut getPointcut() {
        if (null == pointcut) {
            pointcut = new AspectJExpressionPointcut(expression);
        }
        return pointcut;
    }

    @Override
    public Advice getAdvice() {
        return advice;
    }

    public void setAdvice(Advice advice) {
        this.advice = advice;
    }
}
  • AspectJExpressionPointcutAdvisor 实现了 PointcutAdvisor 接口,把切面 pointcut、拦截方法 advice 和具体的拦截表达式包装一起。
    • 这样就可以在 xml 的配置中定义一个 pointcutAdvisor 切面拦截器了。

3.4.4 方法拦截器

MethodBeforeAdviceInterceptor.java

java 复制代码
package com.lino.springframework.aop.framework.adapter;

import com.lino.springframework.aop.MethodBeforeAdvice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

/**
 * @description: 方法拦截器实现类
 */
public class MethodBeforeAdviceInterceptor implements MethodInterceptor {

    private MethodBeforeAdvice advice;

    public MethodBeforeAdviceInterceptor() {
    }

    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
        this.advice = advice;
    }

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        this.advice.before(methodInvocation.getMethod(), methodInvocation.getArguments(), methodInvocation.getThis());
        return methodInvocation.proceed();
    }
}
  • MethodBeforeAdviceInterceptor 实现了 MethodInterceptor 接口,在 invoke 方法中调用 advice 中的 before 方法,传入对应的参数信息。
  • advice.before 则是用于自己实现 MethodBeforeAdvice 接口后做的相应处理。

3.5 代理工厂

3.5.1 切面添加代理配置

AdvisedSupport.java

java 复制代码
package com.lino.springframework.aop;

import org.aopalliance.intercept.MethodInterceptor;

/**
 * @description: 包装切面通知信息
 */
public class AdvisedSupport {
    /**
     * 代理配置
     */
    private boolean proxyTargetClass = false;
    /**
     * 被代理的目标对象
     */
    private TargetSource targetSource;
    /**
     * 方法拦截器
     */
    private MethodInterceptor methodInterceptor;
    /**
     * 方法匹配器(检查目标方法是否符合通知条件)
     */
    private MethodMatcher methodMatcher;

    public boolean isProxyTargetClass() {
        return proxyTargetClass;
    }

    public void setProxyTargetClass(boolean proxyTargetClass) {
        this.proxyTargetClass = proxyTargetClass;
    }

    public TargetSource getTargetSource() {
        return targetSource;
    }

    public void setTargetSource(TargetSource targetSource) {
        this.targetSource = targetSource;
    }

    public MethodInterceptor getMethodInterceptor() {
        return methodInterceptor;
    }

    public void setMethodInterceptor(MethodInterceptor methodInterceptor) {
        this.methodInterceptor = methodInterceptor;
    }

    public MethodMatcher getMethodMatcher() {
        return methodMatcher;
    }

    public void setMethodMatcher(MethodMatcher methodMatcher) {
        this.methodMatcher = methodMatcher;
    }
}

3.5.2 定义代理工厂

ProxyFactory.java

java 复制代码
package com.lino.springframework.aop.framework;

import com.lino.springframework.aop.AdvisedSupport;

/**
 * @description: 代理工厂
 */
public class ProxyFactory {

    private AdvisedSupport advisedSupport;

    public ProxyFactory(AdvisedSupport advisedSupport) {
        this.advisedSupport = advisedSupport;
    }

    public Object getProxy() {
        return createAopProxy().getProxy();
    }

    private AopProxy createAopProxy() {
        if (advisedSupport.isProxyTargetClass()) {
            return new Cglib2AopProxy(advisedSupport);
        }
        return new JdkDynamicAopProxy(advisedSupport);
    }
}
  • 代理工厂主要解决:关于 JDKCglib 两种代理的选择问题,有了代理工厂就可以按照不同的创建需求进行控制。

3.6 融入Bean生命周期的自动代理创建者

3.6.1 实例化感知对象处理

InstantiationAwareBeanPostProcessor.java

java 复制代码
package com.lino.springframework.beans.factory.config;

import com.lino.springframework.beans.BeansException;

/**
 * @description: 实例化感知对象处理
 */
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

    /**
     * 在 Bean 对象执行初始化方法之前,执行此方法
     *
     * @param beanClass 对象类
     * @param beanName  对象名
     * @return 新对象
     * @throws BeansException 异常
     */
    Object postProcessBeforeInitialization(Class<?> beanClass, String beanName) throws BeansException;
}

3.6.2 默认自动代理创建者

DefaultAdvisorAutoProxyCreator.java

java 复制代码
package com.lino.springframework.aop.framework.autoproxy;

import com.lino.springframework.aop.*;
import com.lino.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import com.lino.springframework.aop.framework.ProxyFactory;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.BeanFactory;
import com.lino.springframework.beans.factory.BeanFactoryAware;
import com.lino.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import com.lino.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import java.util.Collection;

/**
 * @description: 默认自动代理创建者
 */
public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {

    private DefaultListableBeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = (DefaultListableBeanFactory) beanFactory;
    }

    @Override
    public Object postProcessBeforeInitialization(Class<?> beanClass, String beanName) throws BeansException {
        if (isInfrastructureClass(beanClass)) {
            return null;
        }

        Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();

        for (AspectJExpressionPointcutAdvisor advisor : advisors) {
            ClassFilter classFilter = advisor.getPointcut().getClassFilter();
            if (!classFilter.matches(beanClass)) {
                continue;
            }
            AdvisedSupport advisedSupport = new AdvisedSupport();

            TargetSource targetSource = null;
            try {
                targetSource = new TargetSource(beanClass.getDeclaredConstructor().newInstance());
            } catch (Exception e) {
                e.printStackTrace();
            }
            advisedSupport.setTargetSource(targetSource);
            advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
            advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
            advisedSupport.setProxyTargetClass(false);

            return new ProxyFactory(advisedSupport).getProxy();
        }

        return null;
    }

    private boolean isInfrastructureClass(Class<?> beanClass) {
        return Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass);
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}
  • 这个 DefaultAdvisorAutoProxyCreator 类的主要核心实现在于 postProcessBeforeInitialization 方法中,通过 beanFactory.getBeanOfType 获取 AspectJExpressionPointcutAdvisor 开始。
  • 获取了 advisors 以后就可以遍历相应的 AspectJExpressionPointcutAdvisor 填充对应的属性信息,包括:目标对象、拦截方法、匹配器,在之后返回代理对象即可。
  • 现在调用方法获取到的这个 Bean 对象就是一个已经被切面注入的对象了,当调用方法的时候,则会被按需拦截,处理用户需要的信息。

3.7 融入到Bean的生命周期

AbstractAutowireCapableBeanFactory.java

java 复制代码
package com.lino.springframework.beans.factory.support;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.*;
import com.lino.springframework.beans.factory.config.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @description: 实现默认bean创建的抽象bean工厂超类
 */
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {

    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
        Object bean = null;
        try {
            // 判断是否返回代理 Bean 对象
            bean = resolveBeforeInstantiation(beanName, beanDefinition);
            if (null != bean) {
                return bean;
            }
            bean = createBeanInstance(beanDefinition, beanName, args);
            // 给bean填充属性
            applyPropertyValues(beanName, bean, beanDefinition);
            // 执行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置处理方法
            bean = initializeBean(beanName, bean, beanDefinition);
        } catch (Exception e) {
            throw new BeansException("Instantiation of bean failed", e);
        }

        // 注册实现 DisposableBean 接口的 Bean 对象
        registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);

        // 判断 SCOPE_SINGLETON、SCOPE_PROTOTYPE
        if (beanDefinition.isSingleton()) {
            registerSingletonBean(beanName, bean);
        }
        return bean;
    }

    private Object resolveBeforeInstantiation(String beanName, BeanDefinition beanDefinition) {
        Object bean = applyBeanPostProcessorsBeforeInstantiation(beanDefinition.getBeanClass(), beanName);
        if (null != bean) {
            bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
        }
        return bean;
    }

    private Object applyBeanPostProcessorsBeforeInstantiation(Class beanClass, String beanName) {
        for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
            if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
                Object result = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).postProcessBeforeInitialization(beanClass, beanName);
                if (null != result) {
                    return result;
                }
            }
        }
        return null;
    }

    ...
}
  • 因为创建的是代理对象不是之前流程里的普通对象,所以我们需要前置于其他对象的创建,既需要在 AbstractAutowireCapableBeanFactory#createBean 优先完成 Bean 对象的判断,是否需要代理,有则直接返回代理对象。

四、测试:把AOP扩展到Bean的生命周期

4.1 添加测试配置

4.1.1 用户自定义拦截方法

UserServiceBeforeAdvice.java

java 复制代码
package com.lino.springframework.test.bean;

import com.lino.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;

/**
 * @description: 用户前拦截器
 */
public class UserServiceBeforeAdvice implements MethodBeforeAdvice {

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("拦截方法:" + method.getName());
    }
}
  • 实现 MethodBeforeAdvice 环绕拦截。在这个方法中我们可以获取到方法的一些信息。

4.1.2 配置文件

spring.xml

xml 复制代码
<?xml version="1.0" encoding="utf-8" ?>
<beans>
    <bean id="userService" class="com.lino.springframework.test.bean.UserService"/>

    <bean class="com.lino.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

    <bean id="beforeAdvice" class="com.lino.springframework.test.bean.UserServiceBeforeAdvice"/>

    <bean id="methodInterceptor" class="com.lino.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor">
        <property name="advice" ref="beforeAdvice"/>
    </bean>

    <bean id="pointcutAdvisor" class="com.lino.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
        <property name="expression" value="execution(* com.lino.springframework.test.bean.IUserService.*(..))"/>
        <property name="advice" ref="methodInterceptor"/>
    </bean>
</beans>
  • 这次使用 AOP 可以像 Spring 中一样,通过在 xml 中配置即可。因为我们已经把 AOP 的功能融合到 Bean 的生命周期里去了,你的新增拦截方法都会被自动处理。

4.2 单元测试

4.2.0 测试环境初始化

ApiTest.java

java 复制代码
public class ApiTest {

    private AdvisedSupport advisedSupport;

    @Before
    public void init() {
        // 目标对象
        IUserService userService = new UserService();
        // 组装代理信息
        advisedSupport = new AdvisedSupport();
        advisedSupport.setTargetSource(new TargetSource(userService));
        advisedSupport.setMethodInterceptor(new UserServiceInterceptor());
        advisedSupport.setMethodMatcher(new AspectJExpressionPointcut("execution(* com.lino.springframework.test.bean.IUserService.*(..))"));

    }
}

4.2.1 前置拦截器测试

ApiTest.java

java 复制代码
@Test
public void test_beforeAdvice() {
    UserServiceBeforeAdvice beforeAdvice = new UserServiceBeforeAdvice();
    MethodBeforeAdviceInterceptor interceptor = new MethodBeforeAdviceInterceptor(beforeAdvice);
    advisedSupport.setMethodInterceptor(interceptor);

    IUserService proxy = (IUserService) new ProxyFactory(advisedSupport).getProxy();
    System.out.println("测试结果:" + proxy.queryUserInfo());
}

测试结果

java 复制代码
拦截方法:queryUserInfo
测试结果:张三,100001,杭州

4.2.2 拦截器访问者测试

ApiTest.java

java 复制代码
@Test
public void test_advisor() {
    // 目标对象
    IUserService userService = new UserService();

    AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
    advisor.setExpression("execution(* com.lino.springframework.test.bean.IUserService.*(..))");
    advisor.setAdvice(new MethodBeforeAdviceInterceptor(new UserServiceBeforeAdvice()));

    ClassFilter classFilter = advisor.getPointcut().getClassFilter();
    if (classFilter.matches(userService.getClass())) {
        AdvisedSupport advisedSupport = new AdvisedSupport();

        TargetSource targetSource = new TargetSource(userService);
        advisedSupport.setTargetSource(targetSource);
        advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
        advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
        advisedSupport.setProxyTargetClass(true);

        IUserService proxy = (IUserService) new ProxyFactory(advisedSupport).getProxy();
        System.out.println("测试结果:" + proxy.queryUserInfo());
    }
}

测试结果

java 复制代码
拦截方法:queryUserInfo
测试结果:张三,100001,杭州

4.2.3 单元测试

ApiTest.java

java 复制代码
@Test
public void test_aop() {
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");

    IUserService userService = applicationContext.getBean("userService", IUserService.class);
    System.out.println("测试结果:" + userService.queryUserInfo());
}

测试结果

java 复制代码
拦截方法:queryUserInfo
测试结果:张三,100001,杭州
  • 从测试结果看,拦截方法已经生效了,也不需要手动处理切面、拦截方法等内容。

五、总结:把AOP扩展到Bean的生命周期

  • 本章实现 AOP 功能的外在体现主要是把以前在单元测试中的切面拦截,交给 Springxml 配置,也就不需要自己手动处理。
    • 如何把相应的功能与 SpringBean 生命周期结合起来,就是用到 BeanPostProcessor
    • 因为它可以解决在 Bean 对象执行初始化方法之前,用于修改新实例化 Bean 对象的扩展点,所以就可以处理 AOP 代理对象逻辑了。
相关推荐
小江的记录本3 分钟前
【JVM虚拟机】JVM调优:常用JVM参数、调优核心指标、OOM排查、GC日志分析、Arthas工具使用(附《思维导图》+《面试高频考点清单》)
java·jvm·spring boot·后端·python·spring·面试
金銀銅鐵16 分钟前
[Java] 用图形化界面演示 iadd, isub, iconst_<i> 指令的效果
java·后端·python
J2虾虾33 分钟前
Spring AI Alibaba文档
java·人工智能·spring
YikNjy39 分钟前
break和continue
java·开发语言·算法
SomeOtherTime41 分钟前
Geojson相关(AI回答)
java·前端·python
日月云棠1 小时前
10 Integer —— 最常用的整数包装类深度解析
java·后端
秋91 小时前
java项目中cpu飙升排查及解决方法
java·开发语言
野生技术架构师1 小时前
牛客网2026最新大厂Java高频面试题精选(附标准答案)
java·开发语言
PH = 71 小时前
JAVA的SPI机制
java·开发语言
一 乐1 小时前
高校实习信息发布网站|基于Spring Boot的高校实习信息发布网站的设计与实现(源码+数据库+文档)
java·数据库·spring boot·后端·论文·毕设·高校实习信息发布网站