概述
Spring经常被人提及的就是IOC和AOP,前边在介绍IOC的时候,我们已经提及到了AOP,还记得起来吗?
在《Spring源码阅读----Spring IoC之finishBeanFactoryInitialization(续)很重要的createBean》一文中,介绍到有些实现了InstantiationAwareBeanPostProcessor接口的AbstractAutoProxyCreator类,其子类AnnotationAwareAutoProxyCreator是个很重要的类。
啥是AOP
AOP(Aspect Oriented Programming),面向切面思想,可以百度一下其概念。比如日志打印等边缘需求会散落在多处业务中,重复写冗余代码会影响项目维护,而AOP就是将这类主业务以外的代码提取出来,使其分离,然后在这些业务中寻找切入点,然后将分离的非业务代码切入业务中。
实践一下
下面来看一个例子,在原来的SSM demo里改造
- 在pom文件中加入依赖包
org.aspectj
aspectjrt
1.9.5
org.aspectj
aspectjweaver
1.9.5
- 创建一个切面类AopTest
@Component
@Aspect
public class AopTest {
@Pointcut("execution(* com.zhlab..ssm.demo.web.controller.TestController.*(..))")
public void pointCut(){}
@Before("pointCut()")
public void beforeMethod(JoinPoint joinPoint){
System.out.println("前置通知before start");
String methodName = joinPoint.getSignature().getName();
System.out.println("前置通知before end");
}
@After("pointCut()")
public void afterMethod(JoinPoint joinPoint){
System.out.println("后置通知after start");
String methodName = joinPoint.getSignature().getName();
System.out.println("后置通知after end");
}
@Around("pointCut()")
public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知after start");
String methodName = joinPoint.getSignature().getName();
Object result = joinPoint.proceed();//执行业务具体业务逻辑
System.out.println("环绕通知after end");
return result;
}
}
类上加上两个注解@Component、@Aspect
注解@Aspect表示当前类是一个切面,添加@Component注解表示当前类需要初始化一个bean到Spring容器中,这个类里只使用了@Before、@After、@Around三个方法注解,总的有以下几个注解:
- @Before注解修饰方法表示当前方法会在连接点方法之前执行
- @After注解修饰方法表示当前方法会在连接点之后执行
- @Around注解修饰方法表示当前方法会在连接点之前和之后均会执行
- @AfterThrowing注解修饰方法表示当前方法会在连接点抛异常之后执行,如果不抛异常则不会执行
- @AfterReturning注解修饰方法表示当前方法会在连接点返回结果时执行,如果连接点方法是void,则该注解不会生效
@Pointcut后可以写execution和@Annotation
execution表达式里的各个号的含义:
"execution( com.zhlab..ssm.demo.web.controller.TestController.*(..))"
- 返回类型: 第一个 * 号的位置:表示返回值类型,* 表示方法返回类型无限制
- 包名以及类:表示需要拦截的包名,TestController指定了具体的类,如果这里改成 ..* 则表示controller包以及其子包下的所有类
- 方法: 第二个 * 号 表示 所有方法,后面括号里面表示方法的参数,两个句点表示任何参数
annotation() 表达式:
"@annotation(org.springframework.web.bind.annotation.GetMapping)"
然后使用该切面的话,就会切入注解是 @GetMapping的所有方法。这种方式很适合处理 @GetMapping、@PostMapping、@DeleteMapping等不同注解有各种特定处理逻辑的场景。
- 在配置文件中加入aop配置信息如下
- 启动项目,然后访问/test,效果如下:
如果method有多个切面的话,我们可以使用@Order(1) 来排序,数字越小排前面。
好了其他的例子就不一一例举了。
很重要的AnnotationAwareAutoProxyCreator
小结
这个标签需要加到spring-mvc的配置代码中才起作用
(头部标签声明需要加入xmlns:aop="http://www.springframework.org/schema/aop",xsi:schemaLocation中需要加入:http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd)
原理
在前文《Spring源码阅读----Spring IoC之BeanFactory、ApplicationContext》中我们介绍过parseBeanDefinitions方法中,会解析自定义标签
//xml解析过程中,调用了自定义标签解析
delegate.parseCustomElement(ele);
//在BeanDefinitionParserDelegate类中执行
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
// 注释1 找到命名空间
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
// 注释2 根据命名空间找到对应的 NamespaceHandler
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
// 注释3 调用自定义的 NamespaceHandler 进行解析
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {
return decorateBeanDefinitionIfRequired(ele, definitionHolder, null);
}
会根据配置中的标签命名空间 获取 对应的NamespaceHandler,这里关注一下
public class AopNamespaceHandler extends NamespaceHandlerSupport {
/**
* Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
* '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
* and '{@code scoped-proxy}' tags.
*/
@Override
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
// 注释 自定义注解,注册解析器,元素名是 aspectj-autoproxy
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace as of 2.1
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}
AspectJAutoProxyBeanDefinitionParser类中关注parse方法:
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
// aop 注解的解析入口,注册 AnnotationAwareAspectJAutoProxyCreator
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
// 对注解中子类的处理
extendBeanDefinition(element, parserContext);
return null;
}
继续看看AopNamespaceUtils类中的registerAspectJAnnotationAutoProxyCreatorIfNecessary如何执行的:
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// 通过工具类,注册或升级 AspectJAnnotationAutoProxyCreator
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 处理 proxy-target-class 以及 expose-proxy 属性
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
// 注册AnnotationAwareAutoProxyCreator组件并通知,让监听器进行处理
registerComponentIfNecessary(beanDefinition, parserContext);
}
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {
if (sourceElement != null) {
// 解析下面两个属性,如果是 true,将它们加入代理注册器的属性列表中
// definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE)
boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
if (proxyTargetClass) {
// 处理 proxy-target-class 属性
// 与代码生成方式有关,在之后步骤中决定使用 jdk 动态代理 或 cglib
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
if (exposeProxy) {
// 处理 expose-proxy 属性
// 扩展增强,有时候目标对象内部的自我调用无法实施切面中的增强,通过这个属性可以同时对两个方法进行增强
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
private static void registerComponentIfNecessary(@Nullable BeanDefinition beanDefinition, ParserContext parserContext) {
if (beanDefinition != null) {
// 注册 的beanName 是 org.springframework.aop.config.internalAutoProxyCreator
parserContext.registerComponent(
new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME));
}
}
所以以上,就是注册AnnotationAwareAutoProxyCreator的过程。aop中创建代理对象是通过AnnotationAwareAutoProxyCreator来实现的。
AnnotationAwareAutoProxyCreator
先来看看AnnotationAwareAutoProxyCreator的类图,如下:
可以看到它的父类AbstractAutoProxyCreator实现了BeanPostProcessor接口的子接口InstantiationAwareBeanPostProcessor,这里关注AbstractAutoProxyCreator执行的postProcessBeforeInstantiation方法和postProcessAfterInitialization方法。
postProcessBeforeInstantiation方法
@Override
public Object postProcessBeforeInstantiation(Class> beanClass, String beanName) {
// 切面 bean 实例化之前执行的方法
// 根据beanClass和beanName获取缓存的key
Object cacheKey = getCacheKey(beanClass, beanName);
// beanName 不存在 || 目标堆中不存在这个 bean
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// 内层判断是否需要进行切面增强,这是个短路操作,判断成功后将跳过后面的操作
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
// 如果我们有自定义 TargetSource,请在此处创建代理。
// 禁止目标bean的不必要的默认实例化:
// TargetSource将以自定义方式处理目标实例
//TargetSource实例相当于就是目标对象bean的封装实例
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
// 获取当前bean所有的增强数组
// 实际上委派给子类去实现 AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// 根据增强数组为目标对象创建代理对象
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
//返回代理bean
return proxy;
}
return null;
}
postProcessAfterInitialization方法
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
// 组装 key
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 如果适合被代理,则需要封装指定的 bean
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
wrapIfNecessary方法源码:
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;
}
// 给定的 bean 类是否代表一个基础设施类,基础设置类不应代理
//或者配置了指定 bean 不需要代理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 如果存在增强方法则创建代理
//获取当前bean所有的增强数组,也就是Advisor数组
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;
}
createProxy方法创建代理对象
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);
// 决定对于给定 bean 是否应该使用 targetClass 而不是他的接口代理
if (!proxyFactory.isProxyTargetClass()) {
// 检查 proxyTargetClass 设置以及 preserveTargetClass 属性
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
// 添加代理接口
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 设置代理工厂属性,将增强数组advisors和目标对象targetSource加入到代理工厂中
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
// 自定义定制代理
customizeProxyFactory(proxyFactory);
// 用来控制代理工厂被配置之后,是否含允许修改通知
// 缺省值为 false,不允许修改代理的配置
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 调用代理工厂类的getProxy方法创建代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}
通过代码执行过程,我们可以发现是委托给ProxyFactory来创建代理对象的。
ProxyFactory的getProxy方法源码:
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
//创建AopProxy对象
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
先是createAopProxy创建AopProxy对象 ,然后通过getProxy获取代理对象
那先来看DefaultAopProxyFactory类中的createAopProxy方法:
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 创建代理
//这里有两种代理类型 1. JDK 动态代理 2. CGLIB 动态代理
// isOptimize 判断是否采用优化策略
//isProxyTargetClass: 该属性对于 标签中的proxy-target-class属性的值.表示是否代理目标类本身,而不是目标类的接口
//hasNoUserSuppliedProxyInterfaces :判断是否存在代理接口
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.");
}
//如果目标对象是一个接口,则创建JDK动态代理对象
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
//如果目标对象不是一个接口,则创建 CGLIB代理对象
return new ObjenesisCglibAopProxy(config);
}
else {
//创建JDK动态代理对象
return new JdkDynamicAopProxy(config);
}
}
如何选择JDK动态代理(JdkDynamicAopProxy )还是CGLIB代理(ObjenesisCglibAopProxy)?
- 如果目标对象实现了接口,默认情况下会采用JDK动态代理;但是可以通过配置 proxy-target-class属性的值为true强制使用CGLIB代理,则代理的是目标对象的本身
- 如果目标对象没有实现接口,那么必须采用CGLIB创建代理对象
JdkDynamicAopProxy 源码:
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
//....前面省略
//JdkDynamicAopProxy 构造函数,设置配置信息
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
} else {
this.advised = config;
}
}
//创建代理对象
public Object getProxy() {
return this.getProxy(ClassUtils.getDefaultClassLoader());
}
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);
this.findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// Proxy.newProxyInstance 动态代理创建对象
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
// 这个熟悉不?因为实现了InvocationHandler接口,所以要重新invoke方法
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// 处理 equals 方法
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);
// Get the interception chain for this method.
// 获取此方法的拦截链
List
ObjenesisCglibAopProxy继承于CglibAopProxy类,其代理对象创建在CglibAopProxy类中实现:
@Override
public Object getProxy() {
// 不传ClassLoader
return getProxy(null);
}
@Override
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...
// 创建CGLIB Enhancer对象,并设置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 ClassLoaderAwareUndeclaredThrowableStrategy(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.
// 调用createProxyClassAndInstance方法创建代理对象
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);
}
}
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
enhancer.setInterceptDuringConstruction(false);
enhancer.setCallbacks(callbacks);
//执行Enhancer的create方法创建代理对象
return (this.constructorArgs != null && this.constructorArgTypes != null ?
enhancer.create(this.constructorArgTypes, this.constructorArgs) :
enhancer.create());
}
CGLIB 是一套强大的高性能的代码生成工具包,底层通过字节码生成技术ASM框架来实现
什么是CGLIB,参考这篇文章《CGLIB动态代理的实现及原理》
从ObjenesisCglibAopProxy创建代理的对象的步骤可以看到:
最终是由Enhancer 对象来创建代理的,传入的Callback数组,可以是实现了MethodInterceptor接口,并重写intercept的拦截器对象。
每次代理对象执行方法,会执行Callback的intercept方法,会通过执行invokeSuper方法来执行目标类的方法。
总结
好了,到这里我们就算完成了对Spring AOP的了解以及原理的分析。