spring源码学习笔记,要点归纳和代码理解
前言
Aop是Spring提供的的另一个核心功能,本节将探讨以下几个问题:
- 什么是AOP,为什么要使用AOP;
- Spring中AOP是如何实现的
一、什么是AOP,为什么要使用AOP
对于某些注入持久化之类 关注面 倾向于横贯某个领域的天然对象边界,原则上可以从模块、封装的角度推理持久化策略。但在实践中,你却不得不将实现了持久化策略的代码铺展到许多对象中。我们用术语横贯式关注面
来形容这类情况。同样,持久化框架和领域逻辑,孤立的看也是可以模块化的。问题在于横贯这些领域的情景。
于是诞生了AOP,AOP为Aspect Oriented Programming的缩写,既面向切面编程。在AOP中,被称为方面(Aspect)的模块构造指明了系统中哪些点的行为会以某种一致的方式被修改,从而支持某种特定的场景。这种说明是用某正简洁的声明或编程机制实现的。
二、Spring中的AOP实现
第一步:注册和解析<aop:aspectj-autoproxy/>
标签
Spring的AOP功能的实现核心类为AnnotationAwareAspectJAutoProxyCreator
,其注册过程是通过自定义标签<aop:aspectj-autoproxy/>
的机械完成的,主要包括以下几步:
- 注册AnnotationAwareAspectJAutoProxyCreator
- 处理proxy-target-class和expose-proxy属性
讲一下proxy-target-class和expose-proxy属性两个属性的作用:
- proxy-target-class:
Spring实现AOP使用JDK动态来历或者CGLIB为目标创建代理,如果目标类实现了至少一个接口,则Spring将使用JDK动态代理,所有目标实现的接口都将被代理。若该目标没有实现任何接口,则创建一个CGLIB代理。想要强制使用CGLIB代理,可以在配置文件中添加<aop:aspcetj-autoproxy proxy-target-class="true"/>
或在配置类上添加注解@EnableAspectJAutoProxy(proxyTargetClass = true)
。使用CGLIB实现代理将无法通知(advise)final方法,因为不能被复写。 - expose-proxy:
有时候目标对象内部的自我调用将无法实施切面中的增强,如下实例:
public class InnerMethodServiceImpl implements InnerMethodService {
@Override
public void methodA() {
this.methodB();
}
@Override
public void methodB() {
System.out.println("method B is invoked");
}
}
切面:
@Aspect
public class InnerMethodAspect {
@Pointcut("execution(* com.pctf.aop.service.InnerMethodService.methodA())")
public void methodAPoint() {
}
@Pointcut("execution(* com.pctf.aop.service.InnerMethodService.methodB())")
public void methodBPoint() {
}
@Before("methodAPoint()")
public void beforeMethodA() {
System.out.println("before method A invoked");
}
@Before("methodBPoint()")
public void beforeMethodB() {
System.out.println("before method B invoked");
}
}
执行结果如图,可见B方法的增强并没有被执行。
解决方法:
- 配置文件中添加
<aop:aspectj-autoproxy expose-proxy="true"/>
- 将代码中的
this.methodB()
调用改为((InnerMethodService)AopContext.currentProxy()).methodB();
可见B方法的增强也被执行了。
第二步:获取增强方法或增强器
AnnotationAwareAspectJAutoProxyCreator
通过实现BeanPostProcessor接口,在bean实例化之后调用postProcessorAfterInitialization方法对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) {
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 List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 获取所有的增强器
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 获取适配当前bean 的增强器
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
增强器的获取主要包括以下几个步骤:
- 获取普通增强器,包括切点信息的获取和根据切点信息生成增强
- 增加同步实例化增强器
- 获取DeclareParents注解
最终生成拦截器链
第三步 创建代理
创建代理的调用栈比较深,这里我就不贴每一步的方法,放一张调用栈的截图
发现其代理类最终通过
DefaultAopProxyFactory
类的createAopProxy
创建代理生成AopProxy对象,然后调用该对象的getProxy
方法获得。拿出createAopProxy方法如下:
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)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
至此,我们看到熟悉的代理生成方法,Jdk代理和Cglib代理了.从if的条件中可以看到三个方面会影响具体使用哪种代理:
- optimize: 用来控制通过Cglib创建的代理是否使用激进的优化策略。除非完全了解AOP代理如何优化,否则不推荐使用这个设置。
- proxytargetclass: 代理目标类本身而不是接口。
- hasNoUserSuppliedProxyInterfaces: 是否存在代理接口
Jdk代理和Cglib代理有什么区别: - Jdk动态代理只能对实现了接口的类生成代理
- Cglib可以针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法。因为是继承,所以类和方法都不应该声明为final
下面来详解下两种代理
Jdk动态代理
public class JdkProxyTest {
public static void main(String[] args) {
LoginService loginService = new LoginServiceImpl();
loginService = (LoginService) getProxy(loginService);
loginService.login("lucifer");
}
public static Object getProxy(Object target) {
ClassLoader classLoader = target.getClass().getClassLoader();
Class<?>[] interfaces = target.getClass().getInterfaces();
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method before invoke");
Object result = method.invoke(target, args);
System.out.println("method after invoke");
return result;
}
};
return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
}
}
上面是一个Jdk代理的实例代码,可以看到实现代理主要包括以下几个步骤:
- 构造函数,传入要代理的对象,这里我直接方法参数传入
- 重写InvocationHandler中的invoke方法,这里包含了所有增强的逻辑
- getProxy方法,传入目标的类加载器,实现的接口和实现的InvocationHandler
Spring中的实现原理与此相同,我们看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);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
InvocationHandler参数传入的是自己,说明自己实现了invoke方法,并且所有的增强逻辑也在此实现.
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 {
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;
// 目标中的自我调用将无法实施增强,通过此属性暴露代理,维护一个ThreadLocal对象,保存当前线程正在创建的代理
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<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...
// 将拦截器封装在ReflectiveMethodInvocation中
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);
}
}
}
其主要逻辑已经注释在代码中了,不再复述。
上面函数最主要的工作是创建了一个拦截器链,并使用ReflectiveMethodInvocation类进行了封装。在proceed方法中注意调用。
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);
}
}
在proceed方法中,维护了拦截器链调用的计数器,依次递归执行拦截器链中的方法.直到执行结束后返回invokeJoinpoint
至此Jdk动态代理结束,返回代理后的对象.
Cglib动态代理
Cglib是一个强大的高性能代码生成包,底层通过使用一个小而快的字节码处理框架ASM,转换字节码并生成新的类。熟悉Jvm的同学应该知道,类的加载并不只依靠.class文件,实际上只要读取一个16进制的字节码文件就可以将类信息加载到Jvm中。
首先来实现一个Cglib代理的实例
public class CglibProxyTest {
public static void main(String[] arge) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(LoginServiceImpl.class);
enhancer.setCallback(new MethodInterceptorImpl());
LoginService loginService = (LoginService) enhancer.create();
loginService.login("lucifer");
}
private static class MethodInterceptorImpl implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before invoke");
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("after invoke");
return result;
}
}
}
包括以下几个步骤:
- 创建增强器Enhancer
- 设置要代理的类
- 设置回调,既要增强的逻辑,实现MethodInterceptor接口的intercept方法
Spring中Cglib的实现与此相同,其逻辑与Jdk实现代理中的invoke方法大同小异,都是先构造拦截器链,然后封装此链递归调用。区别是Cglib中使用CglibMethodInvocation。以下是CglibAopProxy中getProxy方法的代码。
@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...
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.
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);
}
}
网友评论