1.前言
当我们通过在spring的xml配置文件来通过标签来进行aop的相关配置时,需要以下步骤:
- 添加aop的xml nameSpace和dtd约束文件;
- 添加相关配置。
那么现在有一个问题,为什么我们在配置文件中加了aop:config,spring就为相关对象实现的代理,织入了切面。这一过程是怎么样实现的,我就是我们本章要解决的问题。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!--代理的目标对象-->
<bean id="userService" class="com.lihui.study.spring.service.impl.UserServiceImpl" scope="prototype">
<property name="name" value="张学友"/>
</bean>
<!--切面类-->
<bean id="myAspect" class="com.lihui.study.aspect.MyAspect"/>
<!--aop配置-->
<aop:config>
<aop:aspect ref="myAspect">
<aop:pointcut id="pointcut"
expression="execution(* com.lihui.study.spring.service.impl.UserServiceImpl.*(..))"/>
<aop:before pointcut-ref="pointcut" method="doBefore"/>
<aop:after pointcut-ref="pointcut" method="doAfter"/>
</aop:aspect>
</aop:config>
<aop:config>
</aop:config>
<aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>
2.aop:config和 aop:aspectj-autoproxy标签的解析和自动代理构建器的创建。
2.1 将xml解析为Document
对象
此过程不是关键,不详解。
2.2 将Document
对象解析为BeanDefinitions
,并根据<aop>
标签注册相应的自动代理构建器,并注册配置文件中bean定义。
2.2.1 自定义标签的解析分支
DefaultBeanDefinitionDocumentReader.parseBeanDefinitions()
根据是否是默认的命名空间,选择不同解析方式。<aop:config>
明显会进入delegate.parseCustomElement(ele)
分支
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
// 默认命名空间的元素解析
parseDefaultElement(ele, delegate);
}
else {
//自定义命名空间的元素解析
delegate.parseCustomElement(ele);
}
}
}
}
else {
//自定义命名空间的元素解析
delegate.parseCustomElement(root);
}
}
- delegate.parseCustomElement()`
自定义命名空间标签的解析针对aop的命名空间,我们找到的解析处理类为:org.springframework.aop.config.AopNamespaceHandler
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
//获取命名空间,也就是我们xml中配置的xmlns:aop="http://www.springframework.org/schema/aop"
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
//会根据命名空间找到相应的标签处理器。会在项目中所有的META-INO文件夹下寻找spring.handlers文件。然后
//找到通过命名空间找到对应的解析类。针对aop的命名空间,我们会在spring-aop-5.1.2.RELEASE.jar下面找到
//spring.handlers文件,文件内容为:http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
//根据找到的解析处理类解析相应的元素
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
2.2.2 AopNamespaceHandler的初始化和解析过程
AopNamespaceHandler
类的init()
方法和父类NamespaceHandlerSupport
的parse()
方法。
- 在上文的
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri)
,handler对象实例化完成后,会调用init()
方法进行初始化。 NamespaceHandler
实例化和初始化完成后,会调用handler.parse(ele, new ParserContext(this.readerContext, this, containingBd))
,进行相应的解析处理。主要逻辑是通过标签名称找到上面init()方法注册的对应的解析器,然后通过对应的解析器的parse方法进行解析。
public class AopNamespaceHandler extends NamespaceHandlerSupport {
//这里是注册beanDefinition的解析器和装饰器,具体的作用,后面再介绍。
@Override
public void init() {
// In 2.0 XSD as well as in 2.5+ XSDs
//用于2.0和2.5的SSD
//ConfigBeanDefinitionParser解析类,负责解析<ao:config>及里面的<aop:pointcut>、<aop:advisor>、<aop:aspect>标签。
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
//负责解析<aspectj-autoproxy>标签
//其注册的自动代理构建器AnnotationAwareAspectJAutoProxyCreator优先级更高
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace in 2.5+
//仅用于2.0版本,2.5的移到了context 命名空间
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}
2.2.3 <aop:config>
标签的最终解析类 ConfigBeanDefinitionParser
如果是<aop:config>
及其内部标签的解析,则会找到注册的解析器ConfigBeanDefinitionParser
对象,通过器parse()
方法进行解析。
- 开始解析
ConfigBeanDefinitionParser.parse()
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
//这个方法很重要,内部会调用AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary()方法,注册一个自动代理构建器。
configureAutoProxyCreator(parserContext, element);
//解析相关标签
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
if (POINTCUT.equals(localName)) {
parsePointcut(elt, parserContext);
}
else if (ADVISOR.equals(localName)) {
parseAdvisor(elt, parserContext);
}
else if (ASPECT.equals(localName)) {
parseAspect(elt, parserContext);
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
2.创建并注册自动代理构建器的bean定义
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary()
注册一个AspectJAwareAdvisorAutoProxyCreator
的自动代理构建器
public static void registerAspectJAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
//registerOrEscalateApcAsRequired
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
//设置proxyTargetClass的属性值,默认是false,为JDK代理;
//设置exposeProxy的属性值,默认是false。如果设置为true,在调用这个对象的方法时,会将这个代理放入//ThreadLocal中,然后可以通过((UserService)AopContext.currentProxy()).addUser();方式来获取代理
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}
AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary()
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
//先判断注册器中是否包含名字为org.springframework.aop.config.internalAutoProxyCreator的bean定义
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
//比较两个构建器是否相同
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
//如果不同的话,需要比较两个构建器的优先级,保留优先级高的构建器如下
/**
* 在AopConfigUtils类中可以看到优先级别(低-高):
* InfrastructureAdvisorAutoProxyCreator.class
* AspectJAwareAdvisorAutoProxyCreator.class
* AnnotationAwareAspectJAutoProxyCreator.class
**/
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
//如果注册器中没有,则注册一个传入的AspectJAwareAdvisorAutoProxyCreator 的bean定义
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
3. AspectJAwareAdvisorAutoProxyCreator
自动代理构建器
从上一节中,我们已经知道,如果容器中使用了<aop:config>
标签,则注册AspectJAwareAdvisorAutoProxyCreator
的bean定义;如果使用了<aop:aspectj-autoproxy/>
标签,则注册优先级更高的AnnotationAwareAspectJAutoProxyCreator
bean定义。
3.1 类图
AnnotationAwareAspectJAutoProxyCreator
继承了AspectJAwareAdvisorAutoProxyCreator
,下面没有画出。
从图我们可以看出,AnnotationAwareAspectJAutoProxyCreator
实现了BeanPostProfessor
等三个后置处理器接口。
加上前面已经说过,已经注册了相应bean定义。所以,在我们之前介绍过得refresh()
方法中的registerBeanPostProcessors()
中,会注册AnnotationAwareAspectJAutoProxyCreator
对于的bean。
3.2 代理过程
3.2.1 aop代理的入口:BeanPostProcessor
后置处理器
参见我之前的一篇博客,《bea的创建过程》,我们知道,在bean初始化之后,会调用BeanPostProcessor
后置处理器的postProcessAfterInitialization()
方法。代理相关的后置处理器就是AbstractAutoProxyCreator.postProcessAfterInitialization()
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) {
//通过TargetSourceCreator进行自定义TargetSource不需要包装
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
//切面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);
}
}
//设置相应的切面bean,目标对象
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());
}
3.2.2 AopProxy代理的创建:DefaultAopProxyFactory.createAopProxy()
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//如果指定了 optimize为true 或者是proxyTargetClass 为true 或者是 没有实现接口
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.");
}
//目标类是接口 或者是 class是由代理类动态通过getProxyClass方法 或者 newProxyInstance方法生成
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
3.2.3 获取jdk代理对象:JdkDynamicAopProxy.getProxy()
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
//获取所有需要代理的方法
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//创建并返回代理对象,这里需要注意传入的this对象包含了切面(切入点和通知)、回调方法等信息。
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
3.2.4 获取cglib代理对象:CglibAopProxy.getProxy()
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
}
try {
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class<?> proxySuperClass = rootClass;
if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// Validate the class, writing log messages as necessary.
validateClassIfNecessary(proxySuperClass, classLoader);
// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
3.3 代理对象的方法执行
3.3.1 jdk代理对象的执行
根据上文,我们应该不难知道,当调用jdk代理对象的方法方法时候,最后会调用JdkDynamicAopProxy.invoke()
方法。
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.
//目标对象没有实现equals方法,则调用JdkDynamicAopProxy的equals方法
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
//目标对象没有实现hashCode方法,则调用JdkDynamicAopProxy的hashCode方法
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
/**
* method.getDeclaringClass()会返回方法的声明类
* 也就是判断方法的声明类是不是DecoratingProxy接口,DecoratingProxy接口
* 只有一个getDecoratedClass方法。当调用这个方法时候,直接跳转到下面的方法,
* 返回代理对象的真实类型。
**/
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.
// 代理是否需要暴露,前面介绍过,需要的话就把代理放到ThreadLocal中
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.
//回去此方法的拦截链
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);
}
}
}
3.3.1 cglib代理对象的执行
拦截的方法调用,最后会进下面的这个方法,与jdk代理的调用过程大同小异。
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
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);
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// 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 = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
4 使用@Aspect切面配置aop
xml配置文件中需要以下标签:
<context:component-scan base-package="com.xx"
开启注解扫描<aop:aspectj-autoproxy/>
开启aspectj自动代理
编写切面类,使用相关注解。