Spring的AOP组件详解

简介: 该文章主要介绍了Spring AOP(面向切面编程)组件的实现原理,包括Spring AOP的基础概念、动态代理模式、AOP组件的实现以及Spring选择JDK动态代理或CGLIB动态代理的依据。

前言

Spring AOP是基于动态代理模式实现的面向切面编程,非常方便和Spring的组件集成,并且在Spring环境中开发切面功能代码。

动态代理知识回顾

先回忆一下动态代理的知识:

image.png

Spring在选择用JDK还是CGLib的依据

当Bean实现接口时,Spring就会用JDK的动态代理 当Bean没有实现接口时,Spring使用CGLib来实现 可以强制使用CGLib(在Spring配置中加入)

Spring Aop元数据解析

Spring中Aop是怎么基于动态代理实现的?

首先要找到入口,在spring di的时候,bean初始化前后会触发后置处理的回调函数执行。

在下面的AbstractAutowireCapableBeanFactory工厂类中看到bean初始化流程:


//具有自动依赖注入的的bean工厂

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory

implements AutowireCapableBeanFactory {
   
   

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)

throws BeanCreationException {
   
   

// Instantiate the bean.创建bean

BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);

// Initialize the bean instance.

Object exposedObject = bean;

//填充属性

populateBean(beanName, mbd, instanceWrapper);

//触发初始化方法

exposedObject = initializeBean(beanName, exposedObject, mbd);

}

// ....

return exposedObject;

}

//初始化方法

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
   
   

//触发感知赋值spring的基础设施bean

invokeAwareMethods(beanName, bean);

Object wrappedBean = bean;

if (mbd == null || !mbd.isSynthetic()) {
   
   

//应用beanpostprocessor的初始化前回调方法

wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);

}

try {
   
   

//调用初始化方法

invokeInitMethods(beanName, wrappedBean, mbd);

}

catch (Throwable ex) {
   
   

throw new BeanCreationException(

(mbd != null ? mbd.getResourceDescription() : null),

beanName, "Invocation of init method failed", ex);

}

if (mbd == null || !mbd.isSynthetic()) {
   
   

//应用beanpostprocessor的初始化后回调方法

wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

}

return wrappedBean;

}

@Override

public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)

throws BeansException {
   
   

Object result = existingBean;

//应用所有beanpostprocessor的初始化前回调方法

for (BeanPostProcessor processor : getBeanPostProcessors()) {
   
   

Object current = processor.postProcessBeforeInitialization(result, beanName);

if (current == null) {
   
   

return result;

}

result = current;

}

return result;

}

@Override

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)

throws BeansException {
   
   

Object result = existingBean;

for (BeanPostProcessor processor : getBeanPostProcessors()) {
   
   

//应用所有beanpostprocessor的初始化后回调方法

Object current = processor.postProcessAfterInitialization(result, beanName);

if (current == null) {
   
   

return result;

}

result = current;

}

return result;

}

image.png

通过类结构图可知AbstractAutoProxyCreator是Spring Aop模块实现了BeanPostProcessor接口的实现类。

image.png

继续跟进AbstractAutoProxyCreator的postProcessAfterInitialization方法


@Override

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
   
   

if (bean != null) {
   
   

//缓存

Object cacheKey = getCacheKey(bean.getClass(), beanName);

if (this.earlyProxyReferences.remove(cacheKey) != bean) {
   
   

//这个地方可能返回代理

return wrapIfNecessary(bean, beanName, cacheKey);

}

}

return bean;

}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   
   

if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
   
   

return bean;

}

if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
   
   

return bean;

}

if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
   
   

this.advisedBeans.put(cacheKey, Boolean.FALSE);

return bean;

}

// Create proxy if we have advice.

Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

if (specificInterceptors != DO_NOT_PROXY) {
   
   

this.advisedBeans.put(cacheKey, Boolean.TRUE);

//创建一个代理对象。

Object proxy = createProxy(

bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

this.proxyTypes.put(cacheKey, proxy.getClass());

return proxy;

}

this.advisedBeans.put(cacheKey, Boolean.FALSE);

return bean;

}

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,

@Nullable Object[] specificInterceptors, TargetSource targetSource) {
   
   

if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
   
   

AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);

}

ProxyFactory proxyFactory = new ProxyFactory();

proxyFactory.copyFrom(this);

if (!proxyFactory.isProxyTargetClass()) {
   
   

if (shouldProxyTargetClass(beanClass, beanName)) {
   
   

proxyFactory.setProxyTargetClass(true);

}

else {
   
   

evaluateProxyInterfaces(beanClass, proxyFactory);

}

}

//查找匹配的通知

Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);

proxyFactory.addAdvisors(advisors);

proxyFactory.setTargetSource(targetSource);

customizeProxyFactory(proxyFactory);

proxyFactory.setFrozen(this.freezeProxy);

if (advisorsPreFiltered()) {
   
   

proxyFactory.setPreFiltered(true);

}

//获取代理

return proxyFactory.getProxy(getProxyClassLoader());

}

最终调用


public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
   
   

//有两种选择,一个是jdk动态代理,一个是cglib,

@Override

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
   
   

if (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)) {
   
   

//jdk代理

return new JdkDynamicAopProxy(config);

}

//cglib

return new ObjenesisCglibAopProxy(config);

}

else {
   
   

//jdk代码

return new JdkDynamicAopProxy(config);

}

}

/**

* Determine whether the supplied {@link AdvisedSupport} has only the

* {@link org.springframework.aop.SpringProxy} interface specified

* (or no proxy interfaces specified at all).

*/

private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
   
   

Class<?>[] ifcs = config.getProxiedInterfaces();

return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));

}

}

Spring Aop调用流程

//jdk的代理创建好了,调用过程是怎么样的了?

JdkDynamicAopProxy实现了InvocationHandler接口,里面实现了invoke方法,这个方法实现就是代理执行逻辑。


@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类的一些方法

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);

}

//判断是否是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;

//这里是spring提供暴露代理对象的口子,通过设置exposeProxy为true,可以在业务代码中拿到当前代理对象,可以解决比如在同一个service层调用事务方法,事务失效的问题。

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);

// Get the interception chain for this method.

//查找spring容器中,所有的拦截器对象

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.

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 {
   
   

//构造一个调用器

// We need to create a method invocation...

MethodInvocation invocation =

new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);

// Proceed to the joinpoint through the interceptor chain.

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);

}

}

}

//调用器调用逻辑


@Override

@Nullable

public Object proceed() throws Throwable {
   
   

// We start with an index of -1 and increment early.

//是否是最后一个拦截器了,如果是调用目标方法

if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
   
   

return invokeJoinpoint();

}

//获取下一个要执行的拦截器

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 {
   
   

// It's an interceptor, so we just invoke it: The pointcut will have

// been evaluated statically before this object was constructed.

//调用拦截器

return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);

}

}

//拦截器调用图解 通过递归调用,调用所有的拦截器,直到调用到最后一个拦截器时候,调用目标方法。

image.png

相关文章
|
5月前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
617 0
|
9月前
|
监控 安全 Java
Spring AOP实现原理
本内容主要介绍了Spring AOP的核心概念、实现机制及代理生成流程。涵盖切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)等关键概念,解析了JDK动态代理与CGLIB代理的原理及对比,并深入探讨了通知执行链路和责任链模式的应用。同时,详细分析了AspectJ注解驱动的AOP解析过程,包括切面识别、切点表达式匹配及通知适配为Advice的机制,帮助理解Spring AOP的工作原理与实现细节。
1370 13
|
4月前
|
XML Java 数据格式
《深入理解Spring》:AOP面向切面编程深度解析
Spring AOP通过代理模式实现面向切面编程,将日志、事务等横切关注点与业务逻辑分离。支持注解、XML和编程式配置,提供五种通知类型及丰富切点表达式,助力构建高内聚、低耦合的可维护系统。
|
10月前
|
NoSQL 安全 Java
深入理解 RedisConnectionFactory:Spring Data Redis 的核心组件
在 Spring Data Redis 中,`RedisConnectionFactory` 是核心组件,负责创建和管理与 Redis 的连接。它支持单机、集群及哨兵等多种模式,为上层组件(如 `RedisTemplate`)提供连接抽象。Spring 提供了 Lettuce 和 Jedis 两种主要实现,其中 Lettuce 因其线程安全和高性能特性被广泛推荐。通过手动配置或 Spring Boot 自动化配置,开发者可轻松集成 Redis,提升应用性能与扩展性。本文深入解析其作用、实现方式及常见问题解决方法,助你高效使用 Redis。
1068 4
|
11月前
|
安全 Java 数据安全/隐私保护
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 三大核心组件
本课程介绍如何在Spring Boot中集成Shiro框架,主要讲解Shiro的认证与授权功能。Shiro是一个简单易用的Java安全框架,用于认证、授权、加密和会话管理等。其核心组件包括Subject(认证主体)、SecurityManager(安全管理员)和Realm(域)。Subject负责身份认证,包含Principals(身份)和Credentials(凭证);SecurityManager是架构核心,协调内部组件运作;Realm则是连接Shiro与应用数据的桥梁,用于访问用户账户及权限信息。通过学习,您将掌握Shiro的基本原理及其在项目中的应用。
411 0
|
11月前
|
负载均衡 Java Nacos
Spring Cloud五大组件
Spring Cloud五大组件
|
6月前
|
人工智能 监控 安全
如何快速上手【Spring AOP】?核心应用实战(上篇)
哈喽大家好吖~欢迎来到Spring AOP系列教程的上篇 - 应用篇。在本篇,我们将专注于Spring AOP的实际应用,通过具体的代码示例和场景分析,帮助大家掌握AOP的使用方法和技巧。而在后续的下篇中,我们将深入探讨Spring AOP的实现原理和底层机制。 AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的核心特性之一,它能够帮助我们解决横切关注点(如日志记录、性能统计、安全控制、事务管理等)的问题,提高代码的模块化程度和复用性。
|
XML Java 开发者
Spring Boot中的AOP实现
Spring AOP(面向切面编程)允许开发者在不修改原有业务逻辑的情况下增强功能,基于代理模式拦截和增强方法调用。Spring Boot通过集成Spring AOP和AspectJ简化了AOP的使用,只需添加依赖并定义切面类。关键概念包括切面、通知和切点。切面类使用`@Aspect`和`@Component`注解标注,通知定义切面行为,切点定义应用位置。Spring Boot自动检测并创建代理对象,支持JDK动态代理和CGLIB代理。通过源码分析可深入了解其实现细节,优化应用功能。
619 6
|
6月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。