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

文章目录

  • 一、目标:把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 部分,通过拆分后基本可以明确各个类的职责,包括你的代理目标对象属性、拦截器属性、方法匹配属性,以及两种不同的代理操作 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 工程结构

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

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 承担了 PointcutAdvice 的组合。
    • 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;}@Overridepublic Pointcut getPointcut() {if (null == pointcut) {pointcut = new AspectJExpressionPointcut(expression);}return pointcut;}@Overridepublic Advice getAdvice() {return advice;}public void setAdvice(Advice advice) {this.advice = advice;}
}
  • AspectJExpressionPointcutAdvisor 实现了 PointcutAdvisor 接口,把切面 pointcut、拦截方法 advice 和具体的拦截表达式包装一起。
    • 这样就可以在 xml 的配置中定义一个 pointcutAdvisor 切面拦截器了。

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;}@Overridepublic 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);}
}
  • 代理工厂主要解决:关于 JDKCglib 两种代理的选择问题,有了代理工厂就可以按照不同的创建需求进行控制。

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;@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = (DefaultListableBeanFactory) beanFactory;}@Overridepublic 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);}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Overridepublic 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();@Overrideprotected 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_PROTOTYPEif (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 {@Overridepublic 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;@Beforepublic 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 功能的外在体现主要是把以前在单元测试中的切面拦截,交给 Springxml 配置,也就不需要自己手动处理。
    • 如何把相应的功能与 SpringBean 生命周期结合起来,就是用到 BeanPostProcessor
    • 因为它可以解决在 Bean 对象执行初始化方法之前,用于修改新实例化 Bean 对象的扩展点,所以就可以处理 AOP 代理对象逻辑了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/100654.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python综合案例(动态柱状图)

一、基础柱状图 基本代码&#xff1a; """ 演示基础柱状图的开发 """ from pyecharts.charts import Bar from pyecharts.options import LabelOpts # 使用Bar构建基础柱状图 bar Bar() # 添加x轴的数据 bar.add_xaxis(["中国", &q…

js如何实现数组去重的常用方法

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用 Set&#xff08;ES6&#xff09;⭐ 使用 filter 和 indexOf⭐ 使用 reduce⭐ 使用对象属性⭐ 使用 includes 方法&#xff08;ES6&#xff09;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方…

前端开发从 0 到 1 掌握 docker

文章目录 前端从 0 到 1 掌握 docker一、docker 的一些基础概念概念定义question&#xff1a;什么是docker&#xff1f; 为什么要使用docker&#xff1f; 二、实战操作 (墙裂建议读者实操一遍)Part1 - Linux CentOS 服务安装 DockerPart2 - 启动、使用、查看等命令Part3 - 示例…

探索多线程编程:线程的本质、状态和属性

目录 什么是线程线程状态新建线程可运行线程阻塞和等待线程终止线程 线程属性优先级线程名守护线程中断线程未捕获异常的处理器 在现代计算机编程中&#xff0c;多线程是一个重要而强大的概念。它使得我们能够更有效地利用多核处理器、提高程序性能并实现并发操作。 什么是线程…

route命令小结

Destination: 如果不满足该列的任何一个ip,则走默认的default Gataway: *是 不指定gateway.有的系统是0.0.0.0,与*意义相同 Genmask: 0.0.0.0是不指定掩码, 255.255.0.0掩码了16位,172.17 开头的ip,会走这个网关 255.255.255.0掩码了16位,192.168.0 开头的ip都会走这个网关 当是…

探讨前后端分离开发的优势、实践以及如何实现更好的用户体验?

随着互联网技术的迅猛发展&#xff0c;前后端分离开发已经成为现代软件开发的一种重要趋势。这种开发模式将前端和后端的开发工作分开&#xff0c;通过清晰的接口协议进行通信&#xff0c;旨在优化开发流程、提升团队协作效率&#xff0c;并最终改善用户体验。本文将深入探讨前…

sentinel加密狗使用及规则配置

Sentinel加密狗是一种硬件加密设备&#xff0c;用于保护软件应用程序免受未经授权的访问和复制。它可以提供软件许可管理、访问控制和数据保护等功能。下面是Sentinel加密狗的使用及规则配置的相关介绍。 Sentinel加密狗的使用 插入加密狗&#xff1a;将Sentinel加密狗插入计算…

链条输送机如何润滑

润滑是使用机械设备过程中不可或缺的保养工作&#xff0c;链条输送机也不例外&#xff0c;但对于第一次使用链条机的用户来讲&#xff0c;对于哪个部位需要润和以及如何润滑都是一头雾水&#xff0c;今天艾讯就从专业的角度来和您分享一下链条输送机如何润滑的问题。 1、应切断…

爬虫进阶-反爬破解5(selenium的优势和点击操作+chrome的远程调试能力+通过Chrome隔离实现一台电脑登陆多个账号)

目录 一、selenium的优势和点击操作 二、chrome的远程调试能力 三、通过Chrome隔离实现一台电脑登陆多个账号 一、selenium的优势和点击操作 1.环境搭建 工具&#xff1a;Chrome浏览器chromedriverselenium win用户&#xff1a;chromedriver.exe放在python.exe旁边 MacO…

文件上传漏洞

任意文件上传 1. 概述 文件上传是Web 应用必备功能之一&#xff0c;如&#xff0c;头像上传&#xff0c;附件分享等。如果服务器配置不当或者没有进行足够的过滤&#xff0c;Web 用户就可以上传任意文件&#xff0c;包括恶意脚本文件&#xff0c;exe 程序等等&#xff0c;这就…

MySQL 连接出现 Authentication plugin ‘caching_sha2_password‘ cannot be loaded

在使用Navicat Premium 12连接MySQL数据库时会出现Authentication plugin caching_sha2_password cannot be loaded 出错 出现这个原因是mysql8 之前的版本中加密规则是mysql_native_password,而在mysql8之后,加密规则是caching_sha2_password, 解决问题方法&#xff1a;把my…

祝贺埃文科技入选河南省工业企业数据安全技术支撑单位

近日&#xff0c;河南省工业信息安全产业发展联盟公布了河南省工业信息安全应急服务支撑单位和河南省工业企业数据安全技术支撑单位遴选结果,最终评选出19家单位作为第一届河南省工业信息安全应急服务支撑单位和河南省工业企业数据安全技术支撑单位。 埃文科技凭借自身技术优势…