文章目录
- 一、目标:把AOP扩展到Bean的生命周期
- 二、设计:把AOP扩展到Bean的生命周期
- 三、实现:把AOP扩展到Bean的生命周期
- 3.1 工程结构
- 3.2 AOP动态代理融入Bean的生命周期类图
- 3.3 定义Advice拦截器链
- 3.3.1 定义拦截器链接口
- 3.3.2 方法拦截器链接口
- 3.4 定义Advisor访问者
- 3.4.1 定义拦截器访问者接口
- 3.4.2 定义切面拦截器访问者
- 3.4.3 切面访问者实现类
- 3.4.4 方法拦截器
- 3.5 代理工厂
- 3.5.1 切面添加代理配置
- 3.5.2 定义代理工厂
- 3.6 融入Bean生命周期的自动代理创建者
- 3.6.1 实例化感知对象处理
- 3.6.2 默认自动代理创建者
- 3.7 融入到Bean的生命周期
- 四、测试:把AOP扩展到Bean的生命周期
- 4.1 添加测试配置
- 4.1.1 用户自定义拦截方法
- 4.1.2 配置文件
- 4.2 单元测试
- 4.2.0 测试环境初始化
- 4.2.1 前置拦截器测试
- 4.2.2 拦截器访问者测试
- 4.2.3 单元测试
- 五、总结:把AOP扩展到Bean的生命周期
一、目标:把AOP扩展到Bean的生命周期
💡 如何完成AOP和Spring框架的整合?
- 现在通过基于
Proxy.newProxyInstance
代理操作中处理方法匹配和方法拦截,对匹配的对象进行自定义的处理操作。 - 并把这样的技术核心内容拆解到 Spring 中,用于实现 AOP 部分,通过拆分后基本可以明确各个类的职责,包括你的代理目标对象属性、拦截器属性、方法匹配属性,以及两种不同的代理操作 JDK 和 Cglib 的方式。
- 在有了一个 AOP 核心功能的实现后,我们通过单元测试的方式进行验证切面功能对方法进行拦截,但如果这是一个面向用户使用的功能,就不太可能让用户这么复杂且没有与 Spring 结合的方式单独使用 AOP。
- 因此我们需要完成 AOP 核心功能和 Spring 框架的整合,最终能通过在 Spring 配置的方式完成切面的操作。
二、设计:把AOP扩展到Bean的生命周期
💡 怎么借着 BeanPostProcessor 把动态代理融入到 Bean 的生命周期中,以及如何组装各项切点、拦截、前置的功能和适配对应的代理器?
- 为了可以让对象创建过程中,能把 xml 中配置的代理对象(切面)的一些类对象实例化,就需要用到
BeanPostProcessor
提供的方法。- 因为这个类中的方法可以分别作用与 Bean 对象执行初始化前后修改 Bean 的对象的扩展信息。
- 但这里需要于
BeanPostProcessor
实现新的接口和实现类,这样才能定向获取对应的类信息。
- 因为创建的代理对象不是流程里的普通对象,所以需要前置于其他对象的创建。
- 实际开发中,需要在
AbstractAutowireCapableBeanFactory#createBean
优先完成 Bean 对象的判断,是否需要代理,有则直接返回代理对象。
- 实际开发中,需要在
- 还需要解决方法拦截器的具体功能,提供一些
BeforeAdvice、AfterAdvice
的实现,让用户可以更简化的使用切面对象。 - 除此以外还包括:需要包装切面表达式以及拦截方法的整合、提供不同类型的代理方式的代理工厂,来包装切面服务。
三、实现:把AOP扩展到Bean的生命周期
3.1 工程结构
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
会依赖于拦截器、代理工厂和Pointcut
与Advisor
的包装服务AspectJExpressionPointcutAdvisor
,由它提供切面、拦截方法和表达式。- Spring AOP 把
Advice
细化了BeforeAdvice
、AfterAdvice
、AfterReturningAdvice
、ThrowsAdvice
。
3.3 定义Advice拦截器链
3.3.1 定义拦截器链接口
BeforeAdvice.java
package com.lino.springframework.aop;
import org.aopalliance.aop.Advice;
/**
* @description: 拦截器链
*/
public interface BeforeAdvice extends Advice {
}
3.3.2 方法拦截器链接口
MethodBeforeAdvice.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
package com.lino.springframework.aop;
import org.aopalliance.aop.Advice;
/**
* @description: 拦截器访问者
*/
public interface Advisor {
/**
* 获取拦截器
*
* @return 拦截器
*/
Advice getAdvice();
}
3.4.2 定义切面拦截器访问者
PointcutAdvisor.java
package com.lino.springframework.aop;
/**
* @description: 切面拦截器访问者
*/
public interface PointcutAdvisor extends Advisor {
/**
* 获取切面
*
* @return 切面
*/
Pointcut getPointcut();
}
- PointcutAdvisor 承担了
Pointcut
和Advice
的组合。Pointcut
:用于获取JoinPoint
。Advice
:决定JoinPoint
执行什么操作。
3.4.3 切面访问者实现类
AspectJExpressionPointcutAdvisor.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
切面拦截器了。
- 这样就可以在 xml 的配置中定义一个
3.4.4 方法拦截器
MethodBeforeAdviceInterceptor.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
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
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);
}
}
- 代理工厂主要解决:关于 JDK 和 Cglib 两种代理的选择问题,有了代理工厂就可以按照不同的创建需求进行控制。
3.6 融入Bean生命周期的自动代理创建者
3.6.1 实例化感知对象处理
InstantiationAwareBeanPostProcessor.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
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
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
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 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
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
@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());
}
测试结果
拦截方法:queryUserInfo
测试结果:张三,100001,杭州
4.2.2 拦截器访问者测试
ApiTest.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());
}
}
测试结果
拦截方法:queryUserInfo
测试结果:张三,100001,杭州
4.2.3 单元测试
ApiTest.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());
}
测试结果
拦截方法:queryUserInfo
测试结果:张三,100001,杭州
- 从测试结果看,拦截方法已经生效了,也不需要手动处理切面、拦截方法等内容。
五、总结:把AOP扩展到Bean的生命周期
- 本章实现 AOP 功能的外在体现主要是把以前在单元测试中的切面拦截,交给 Spring 的 xml 配置,也就不需要自己手动处理。
- 如何把相应的功能与 Spring 的 Bean 生命周期结合起来,就是用到
BeanPostProcessor
。 - 因为它可以解决在 Bean 对象执行初始化方法之前,用于修改新实例化 Bean 对象的扩展点,所以就可以处理 AOP 代理对象逻辑了。
- 如何把相应的功能与 Spring 的 Bean 生命周期结合起来,就是用到