springAOP简介
AOP(Aspect Oriented Program):即面向切面编程
在面向切面编程的思想里面,把功能分为核心业务功能和周边功能
- 所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务
- 所谓的周边功能,比如性能统计,日志,事务管理等等
在SpringAOP中将这些周边功能称为切面,将核心业务逻辑与这些周边功能分别独立开始,然后将它们交织在一起就是AOP需要做的事情
AOP将业务模块锁公共调用的、非业务逻辑的功能封装起来;这样的好处?
一:所以这些非核心业务功能都集中在一起,而不是分散到多处代码中,便于减少系统的重复代码,降低模块间的耦合度,有利于维护
二:服务模块更简洁,因为它们只包含主要关注点或核心功能的代码,次要的非业务功能(周边功能)被转移到切面中
AOP当中的概念
连接点(JoinPoint):在程序执行过程中某个特定的点,比如类初始化前、类初始化后,方法调用前,方法调用后;
切点(Pointcut):所谓切点就是你所切取的类中的方法,比如你横切的这个类中有两个方法,那么这两个方法都是连接点,对这两个方法的定位就称之为切点;
增强(Advice):增强是织入到连接点上的一段程序,另外它还拥有连接点的相关信息;
目标对象(Target):增强逻辑的织入目标类,就是我的增强逻辑植入到什么位置;
引介(Introduction):一种特殊的增强,它可以为类添加一些属性喝方法;
织入(Weaving):织入就是讲增强逻辑添加到目标对象的过程;
代理(Proxy):一个类被AOP织入增强后,就会产生一个结果类,他是融合了原类和增强逻辑的代理类;
切面(Aspect):切面由切点和增强组成,他是横切逻辑定义和连接点定义的组成;
相关注解说明
- @Apsect: 将当前类标识为一个切面;
- @Pointcut: 公共切入点:使用方式 eg: @Before(value = “pointCut()”)
- @Before:前置通知,就是在目标方法执行之前执行;
- @AfterReturning:后置通知,方法退出时执行;
- @AfterThrowing: 异常通知,有异常时该方法执行;
- @After: 最终通知,无论什么情况都会执行;
- @Afround: 环绕通知;在目标方法执行的前后进行执行
execution表达式说明:
eg: @Pointcut(value = “execution(* com.compass.aop.test…* .*(…))”)
- 标识符 含义
- execution() 表达式的主体
- 第一个“*”符号 表示返回值的类型任意
- com.smartplg.interview.test AOP所切的服务的包名,即,需要进行横切的业务类
- 包名后面的“…” 表示当前包及子包
- 第二个“*” 表示类名,*即所有类
- .*(…) 表示任何方法名,括号表示参数,两个点表示任何参数类型
annotation: 匹配指定注解
@annotation(anno.RequiredAnnotationClass) 匹配有此注解[@RequiredAnnotationClass]描述的方法
简单易懂的图就是:
假设我要在用户登录后做日志记录,大致的流程图就是:
AOP基本使用
有了以上的前置知识,我们就可以使用spring的AOP功能进行编程了,相关的依赖自己进行百度导入,使用springBoot的话,引入依赖比较简单。我们使用注解的方式来完成AOP切面,xml太繁琐了,有兴趣的可以自己看下xml版本的。
1.定义一个配置类,定义扫描规则,开启AOP功能
@EnableAspectJAutoProxy
@Configuration // 配置类
@ComponentScan("com.compass.aop.test") // 标识扫描的路径
public class AppConfig {
}
2.定义一个登录接口
public interface UserService {
/**
* 登录接口 [模拟,真实的时候是需要连接数据库查询的]
* @param username
* @param password
* @return
*/
String login(String username,String password);
}
3.对登录接口实现
@Service
public class UserServiceImpl implements UserService {
@Log(title = "loginOperation") //此注解是自定义注解,表示是开启记录日志功能
@Override
public String login(String username, String password) {
System.out.println("login 被执行...");
// 打开此注释即可看到异常通知
// int age = 10/0;
if ("admin".equals(username) && "123".equals(password)){
return "login success";
}
return "login failed";
}
}
4.自定注解
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EnableLog{
public String value() default "yes";
}
4.定义切面 对login(String username, String password) 方法进行增强
@Aspect // 表示这是一个切面
@Component // 将这个切面添加到spring容器中
public class LogAspect {
// 公共切入点 使用方式 @Before(value = "pointCut()")
@Pointcut(value = "execution(* com.compass.aop.test..* .*(..))")
private void pointCut() {
}
// 前置通知
@Before(value = "pointCut()")
public void doBefore(JoinPoint joinPoint) {
System.out.println("前置通知[execution]");
}
// 后置通知 在指定注解下执行
@AfterReturning(value = "@annotation(serviceLog)", returning = "result")
public void doAfterReturning(JoinPoint joinPoint, EnableLog serviceLog, String result) {
System.out.println("后置通知:"+result+" Log-value:"+serviceLog.value());
// 如果我们注解标注的值为value 我们可以在此处记录用户的日志信息
if (serviceLog.value()){
// 获取到方法参数的value 如果是真实环境我们就可以将日志记录到数据库或者文件中
Object[] args = joinPoint.getArgs();
System.out.println(args);
}
}
// 最终通知
@After(value = "pointCut()")
public void doAfter(JoinPoint joinPoint) throws NoSuchMethodException {
System.out.println("最终通知: ");
//当前调用的方法签名
Signature signature = joinPoint.getSignature();
MethodSignature msg=(MethodSignature) signature;
Object target = joinPoint.getTarget();
//获取注解标注的方法
Method method = target.getClass().getMethod(msg.getName(), msg.getParameterTypes());
//通过方法获取注解
EnableLog annotation = method.getAnnotation(EnableLog.class);
//获取参数
Object[] args = joinPoint.getArgs();
}
// 异常通知
@AfterThrowing(value = "pointCut()",throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint ,Throwable e) {
System.out.println("异常通知 :"+e.getMessage());
}
//环绕通知 注意要有ProceedingJoinPoint参数传入
@Around(value = "pointCut()")
public Object doAround(ProceedingJoinPoint point) throws Throwable {
System.out.println("环绕通知..环绕前");
// 执行目标方法 不写这行代码 目标方法不会被执行
// 如果有返回值,一定要return出去,否则自己的业务方法得不到返回值
Object result = point.proceed();
System.out.println("环绕通知..环绕后");
return result;
}
}
测试类
public class MyTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean( "userServiceImpl",UserService.class);
String result = userService.login("admin", "123");
System.out.println("登录结果:"+result);
}
}
注意点:
- 环绕通知一定要调用 point.proceed() 方法进行执行目标方法,不然我们的目标方法不会被执行
- 环绕通知如果有返回值,我们也需要获取到返回值,return出去,否则我们调用目标方法的时候得不到结果
AOP通知的执行顺序
我们来看下这些通知的一个指向流程:
正常的执行逻辑:
- 执行环绕通知的前置逻辑
- 执行前置通知
- 执行目标方法
- 执行后置通知
- 执行最终通知
- 执行环绕通知的后置逻辑
出现异常的执行逻辑:
- 执行环绕通知的前置逻辑
- 执行前置通知
- 执行目标方法
- 出现异常,执行异常通知,出现异常返回通知和环绕通知的后置逻辑就不会被执行了
- 执行最终通知
多个切面时的执行流程:
springAOP在真实开发中可以做什么?
我这里给大家举几个例子: 反正你就可以理解为,你可以在你的业务逻辑的任何方法执行的时候进行干扰,也就是增强,你可以获取到该方法运行时的参数,可以做一些具体的操作,具体怎么操作是由你的决定的,springAOP在执行方法的同时把控制器交给你,这也是很多框架的特点,在执行原有逻辑的基础上,给你留有接口,或者是能让你对执行过程可以进行干扰。
- 记录用户的操作记录
- 事务管理
- 防重复提交
- 做数据缓存
- 权限验证
- 数据校验
进阶-代理模式之JDK动态代理
代理模式有两种实现:
- jdk动态代理:jdk原生API,jdk动态代理是由java内部的反射机制来实现的,[如果你实现了接口那么就是动态代理]
- cglib代理:使用第三方jar包,cglib动态代理底层则是借助asm来实现,[ 如果没有实现接口是用的cglib代理 ]
空口无凭,看源码说话,这也就是我们可以实现接口,也可以不实现接口都能完成AOP切入功能的硬核所在
// 创建一个AOP代理
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// 先获取到代理工厂,让后再去创建代理对象
return getAopProxyFactory().createAopProxy(this);
}
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (!NativeDetector.inNativeImage() &&
(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
// 如果你的目标类是一个接口,那么使用动态代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
// 创建一个动态代理对象返回
return new JdkDynamicAopProxy(config);
}
//如果不是的话,那就使用cglb进行创建代理对象
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
JDK动态代理的执行方式:
public class JDKDynamicProxy {
/**
* 使用jdk的反射机制创建出一个代理对象
* @param target 需要创建代理的对象
* @return 代理对象
*/
public static <T> T getTransactionProxyInstance(Object target,Class<T> clazz){
Object proxyInstance = Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), new InvocationHandler() {
/**
* 三个参数:1、代理对象,2、目标对象的方法,3、目标对象的参数值列表
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行目标业务逻辑之前"); //执行核心业务之前执行的内容
Object result = method.invoke(target, args); //执行目标对象方法,即核心业务
System.out.println("执行目标业务逻辑之后"); //执行核心业务之后执行的内容
return result;
}
});
return (T)proxyInstance;
}
}
调用测试
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
UserService userServiceProxy = JDKDynamicProxy.getTransactionProxyInstance(userService, UserService.class);
System.out.println("结果:"+userServiceProxy.login("admin", "123"));
// 一个是真实的对象,一个jdk动态创建的代理对象,根本都不是同一个对象
System.out.println(userService == userServiceProxy );
}
输出结果:
执行目标业务逻辑之前
login 被执行... [目标方法被执行]
执行目标业务逻辑之后
结果:login success
false
进阶-SpringAOP原理
1.我们先来看下这个@EnableAspectJAutoProxy 这个注解做了什么事情
他往容器中导入了一个 AspectJAutoProxyRegistrar.class 组件
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
AspectJAutoProxyRegistrar.class做了什么事情?
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 在此处导入了 AnnotationAwareAspectJAutoProxyCreator.class
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
然后我们的 AppConfig 早在 this() [ 也就是AnnotationConfigApplicationContext构造器的时候 ],的时候就添加到beanDefinitionMap中去了,然后在 invokeBeanFactoryPostProcessors(beanFactory);后置处理器的时候,就会去容器中找到所有配置类,并且解析。
invokeBeanFactoryPostProcessors(beanFactory)做的事情:
1.拿到工厂中的所有Bean定义信息(后置处理器(第一步的那几个)+配置类)
2.找到真正的配置类
3.使用parse进行配置类解析包扫描所有组件进来
4.1 scanner扫描包路径下的所有类,判断是否扫描范围内的,如果是就封装成4.ScannedGenericBeanDefinition添加到需要返回的组件集合中(@Lazy等注解会在这一步解析,保存到当前Bean的定义信息【BeanDefinition】中)
5.除了会处理@ComponentScan注解还能处理【@PropertySource、@lmport 、@lmportResource、】
执行完 invokeBeanFactoryPostProcessors(beanFactory) 我们的beanDefinitionMap中就有了Bean的定义信息了
等处理完,我们就可以看到 beanDefinitionMap 中了 AnnotationAwareAspectJAutoProxyCreator 的定义
AnnotationAwareAspectJAutoProxyCreator 他的职责就是看看那些类需要添加到 advisedBeans
在容器刷新的12大步骤中,registerBeanPostProcessors(beanFactory),会注册所有实现了BeanPostProcessors接口的类,然后我们的AnnotationAwareAspectJAutoProxyCreator就会被创建并且添加到容器中。
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
// 先从容器中获取到 所有实现了 BeanPostProcessor 接口的beanName
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
// 处理实现了 PriorityOrdered接口的BeanPostProcessor
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// 进行排序
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 注册到beanPostProcessors中
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// 处理实现了 Ordered 的BeanPostProcessor
// 我们的AnnotationAwareAspectJAutoProxyCreator是实现了Ordered接口的会在此处进行处理
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String ppName : orderedPostProcessorNames) {
// 调用 getBean() 创建我们的AnnotationAwareAspectJAutoProxyCreator对象 经过生命周期
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// 没有实现任何排序接口的BeanPostProcessor
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// Finally, re-register all internal BeanPostProcessors.
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
然后接下来所有的bean创建的流程都会经过AnnotationAwareAspectJAutoProxyCreator的父类AbstractAutoProxyCreator的postProcessBeforeInstantiation() 的处理,会在每个bean的创建过程中会判断那些是切面需要加入到advisedBeans
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
//advisedBeans用于存储不可代理的bean,如果包含直接返回
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
//判断当前bean是否可以被代理,然后存入advisedBeans
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
//获取封装当前bean的TargetSource对象,如果不存在,则直接退出当前方法,否则从TargetSource
// 中获取当前bean对象,并且判断是否需要将切面逻辑应用在当前bean上。
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
// 获取能够应用当前bean的切面逻辑
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
// 对生成的代理对象进行缓存
this.proxyTypes.put(cacheKey, proxy.getClass());
//如果最终可以获得代理类,则返回代理类,直接执行实例化后置通知方法
return proxy;
}
return null;
}
AnnotationAwareAspectJAutoProxyCreator 他还实现了 BeanFactoryAware 会拿到整个beanFactory
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
if (this.aspectJAdvisorFactory == null) {
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
}
this.aspectJAdvisorsBuilder =
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}
在初始化期间使用InitializingBean准备好基本的属性
利用BeanFactoryAware 接口 准备好ReflectiveAspectJAdvisorFactory 和BeanFactoryAspectJAdvisorsBuilderAdapter
ReflectiveAspectJAdvisorFactory (创建增强器的工厂,他们负责保存增强器)
BeanFactoryAspectJAdvisorsBuilderAdapter(增强器建造者,产生功能增强器)
如何找到切面?
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
// 第一次运行的时候,不知道谁是切面,把容器中的所有组件获取到挨个进行比对,看看谁是切面,添加到缓存中
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
// 双重检测锁
synchronized (this) {
aspectNames = this.aspectBeanNames;
// 如果切面的集合为空
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
// 从容器中获取到所有的beanNames
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
Class<?> beanType = this.beanFactory.getType(beanName, false);
if (beanType == null) {
continue;
}
// 判断当前bean是否是切面,如果是添加到aspectNames
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 利用反射获取到切面中的所有的方法,找出增强方法 [可以点进去看看是怎么封装的]
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
// 将切面中的所有增强方法信息添加到advisors
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
一个 Advisor 就是一个增强器保存当前切入点表达式和当前方法的详细信息
这样我们的切面和切入点信息就已经准备完毕,接下来就是别的bean在创建的过程当中由AnnotationAwareAspectJAutoProxyCreator判断要不要给其创建代理对象,也就是看看切面能不能切入这个bean。
在bean属性初始化完毕后开始创建的代理对象,会在此处判断当前对象如果有切面能切切入,那么就创建代理对象。
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 检测是否需要创建代理对象,如果需要使用cglib创建代理对象进行返回
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// 使用原生的jdk动态代理创建代理对象
return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}
进阶-AOP运行原理
只要我们执行目标方法,就会被 JdkDynamicAopProxy拦截到,JdkDynamicAopProxy实现了InvocationHandler拦截接口
@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 {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 通过当前执行的方法和当前class类型,找到该方法的一个拦截器链,也就是我们在切面写的那些通知
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
// 如果你没有任何通知切入你,那么就直接利用反射调用目标方法,就不再去创建MethodInvocation
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 此处相当于创建一个调用者,里面会封装很多信息
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
// 获取到了invocation后,就可以进行AOP拦截的整个流程了
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
通过当前执行的目标方法和当前类的class获取到调用链
我们真正的方法调用者,他里面封装了很多信息,有目标对象,代理对象,目标方法,当前方法的参数,有了这些信息,我们完全可以利用反射去调用目标方法
接下来我们就分析他是如何进行一步一步调用的,他是一个递归调用,子类父类之间相互调用的一个过程。
坐稳了,开始发车了,前方高能,这就是通知执行流程的一个原因所在,什么时候执行什么通知,都是由接下来的逻辑确定的
@Override
@Nullable
public Object proceed() throws Throwable {
// currentInterceptorIndex 第一次为 -1,
// interceptorsAndDynamicMethodMatchers:所有可以拦截当前方法执行的通知都在里面,有几个通知size就为几
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 这个是调用连接点,这就是递归的结束条件,当interceptorsAndDynamicMethodMatchers大小为-1的时候
// 说明调用链已经准备完毕,可以开始逐步进行调用
return invokeJoinpoint();
}
// 他让当前的这个索引+1,那就就是获取到拦截器列表中的第一个拦截器了
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// 我们的通知还是一个MethodInterceptor,他可以去调用invoke(this)方法
// 把ReflectiveMethodInvocation实例给传递过去了,里面有封装很多信息,我们上面有提到过
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
可以到,第一次进来,我们有6个通知,可以切入到我们的 login()方法
接着调用到 invoke()方法
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
// 第一次默认是null
MethodInvocation oldInvocation = invocation.get();
// 他把传递过来的ReflectiveMethodInvocation使用ThreadLocal对象保存起来,达到一个线程之间隔离的效果
invocation.set(mi);
try {
// mi就是我们的ReflectiveMethodInvocation,一调用就调用到ReflectiveMethodInvocation.proceed()方法去了
return mi.proceed();
}
finally {
// 在执行完毕后,设置为null,避免内存泄漏
invocation.set(oldInvocation);
}
}
我们让其递归调用结束,也就是我们的currentInterceptorIndex==我们通知列表的大小的时候,说明该退出递归,去执行对应的调用链了。这个递归调用过程有点难说清楚,还是个人debug看嘛,你看看对象的比变化过程,那些通知分别是在说明位置执行的就行,最后使用的是jdk底层的invoke()方法执行的目标方法。我个大家一张参考图,大家自行进行debug,自己debug看源码才是精髓。
可以到,第一次进来,我们有6个通知,可以切入到我们的 login()方法
接着调用到 invoke()方法
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
// 第一次默认是null
MethodInvocation oldInvocation = invocation.get();
// 他把传递过来的ReflectiveMethodInvocation使用ThreadLocal对象保存起来,达到一个线程之间隔离的效果
invocation.set(mi);
try {
// mi就是我们的ReflectiveMethodInvocation,一调用就调用到ReflectiveMethodInvocation.proceed()方法去了
return mi.proceed();
}
finally {
// 在执行完毕后,设置为null,避免内存泄漏
invocation.set(oldInvocation);
}
}
我们让其递归调用结束,也就是我们的currentInterceptorIndex==我们通知列表的大小的时候,说明该退出递归,去执行对应的调用链了。这个递归调用过程有点难说清楚,还是个人debug看嘛,你看看对象的比变化过程,那些通知分别是在说明位置执行的就行,最后使用的是jdk底层的invoke()方法执行的目标方法。我个大家一张参考图,大家自行进行debug,自己debug看源码才是精髓。
这张大致图描述了SpringAOP的一个流程,可以配合debug进行调试,图有点大,可以放大仔细看,因为框架的源代码逻辑比较复杂,难免会导致分析图也有点复杂,想要理解,就得认真反复看,看几次就属性了,到了面试的时候,你就能跟面试官两个扯,毫无压力。