1. 背景

在前文Spring IOC容器创建bean过程浅析已经介绍了Spring IOC创建初始化bean的大致过程。现在对Spring的AOP实现机制进行研究分析。

2. 名词与概念

名词 概念
Advice 通知,在连接点的处理逻辑
Advisor Advisor可以简单理解为Advice+PointCut
Interceptor 拦截器
Aspect 切面

3. 代理类创建的入口--AbstractAutoProxyCreator

AbstractAutoProxyCreator是Spring AOP实现的一个很重要的抽象类。下面是它的继承层次。

我们可以注意到,它其实是一个BeanPostProcessor。我们需要重点关注的方法是其中的wrapIfNecessary方法,可以说这是Spring实现Bean代理的核心方法。

wrapIfNecessary在两处会被调用,一处是getEarlyBeanReference,另一处是postProcessAfterInitialization。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 判断是否不应该代理这个bean。
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
/*
* 判断是否是一些InfrastructureClass或者是否应该跳过这个bean。
* 所谓InfrastructureClass就是指Advice/PointCut/Advisor等接口的实现类。
* shouldSkip默认实现为返回false,由于是protected方法,子类可以覆盖。
*/
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
} // 获取这个bean的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;
} // 这个bean不需要被代理。
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
} protected Object createProxy(
Class<?> beanClass, String beanName, 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);
for (Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
} proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
} return proxyFactory.getProxy(getProxyClassLoader());
}

4. 代理类创建的实现

从上面的createProxy方法中,我们可以看到,最终Spring是通过ProxyFactory#getProxy的调用来获取最终的代理bean的。



下面就来看一下这其中的过程。

public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
} /**
* 该方法是ProxyCreatorSupport(ProxyFactory的基类)的保护方法。
*/
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
} return getAopProxyFactory().createAopProxy(this);
}

DefaultAopProxyFactory是AopProxyFactory接口的默认实现,下面来看一下其中createAopProxy方法的实现。Spring就是在这里判断是使用JDK动态代理还是cglib代理的。

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
/*
* 这里是Spring判断是用JDK动态代理还是Cglib代理的依据。
* 1. optimize开关被设置为true。此开关默认为false。
* 2. proxyTargetClass开关为true。
* 3. 没有用户代理接口。所谓用户代理接口就是指非Spring生成的代理。
*
* 满足上述三点任意一点就会根据代理类本身
*/
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.");
}
// 如果targetClass本身是个接口或者targetClass是JDK Proxy生成的,则使用JDK动态代理。
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 否则使用Cglib代理。
return new ObjenesisCglibAopProxy(config);
}
else {
// 使用JDK动态代理。
return new JdkDynamicAopProxy(config);
}
}

4.1 JDK动态代理--JdkDynamicAopProxy的源码分析

public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

可以看到本质上JdkDynamicAopProxy对于AopProxy的getProxy方法的实现本质上是调用我们熟悉的Proxy.newProxyInstance来生成代理bean。

而JdkDynamicAopProxy本身也实现了InvocationHandler接口。下面就来看下它对InvocationHandler#invoke的实现。

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null; try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// 方法为equals且代理bean本身没有实现equals方法。
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// 方法为hashCode且代理bean本身没有实现hashCode方法。
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
} Object retVal; if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
} target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
} // 获取该方法对应的拦截器链。
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // 如果没有任何拦截器,则通过反射调用对应方法。
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 创建方法调用链。
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 调用方法联。
retVal = invocation.proceed();
} Class<?> returnType = method.getReturnType();
// 如果返回的是this,则判断是否需要把retVal设置为代理对象。
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
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()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}

4.2 cglib代理--CglibAopProxy的源码分析

Spring对于cglib创建代理,内部默认使用ObjenesisCglibAopProxy来创建代理bean,它是CglibAopProxy的子类,并且重写了createProxyClassAndInstance方法。Objenesis是一个类库,可以绕过构造器创建对象。

cglib使用Enhancer来生成代理类,生成的类实质上是被代理类的子类。更多关于Enhancer的信息,可以参考我的博文cglib之Enhancer

public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
} try {
// advised其实就是创建CglibAopProxy的时候构造参数中传递的config配置。
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy"); Class<?> proxySuperClass = rootClass;
if (ClassUtils.isCglibProxyClass(rootClass)) {
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
} validateClassIfNecessary(proxySuperClass, classLoader); Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
// 配置enhancer如代理接口,回调等。
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader)); // 这里生成callback方法的逻辑是阅读源码的重点。
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
} // callbackFilter的作用主要是建立了method与callback编号的映射。
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types); // 生成代理的class以及代理bean实例。
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
this.advised.getTargetClass() + "]: " +
"Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
this.advised.getTargetClass() + "]: " +
"Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Exception ex) {
throw new AopConfigException("Unexpected AOP exception", ex);
}
}

4.2.1 CglibAopProxy生成callbacks

在CglibAopProxy内部定义了一组常量用于表示生成的callback索引。

  • AOP_PROXY = 0

    一般的aop调用
  • INVOKE_TARGET = 1

    直接调用目标方法
  • NO_OVERRIDE = 2

    不能覆盖的方法,比如finalize方法。
  • DISPATCH_TARGET = 3

    直接对原来的bean进行方法调用。
  • DISPATCH_ADVISED = 4

    对Advised接口方法有效
  • INVOKE_EQUALS = 5

    对equals方法拦截
  • INVOKE_HASHCODE = 6

    对hashCode方法拦截

接下来就看一下这些callback生成的具体源码实现。

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// Parameters used for optimisation choices...
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic(); // 对于AOP方法的调用,使用DynamicAdvisedInterceptor拦截器。
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised); /*
* 不需要增强,但可能会返回this的方法:
* 如果targetSource是静态的话(每次getTarget都是同一个对象),使用StaticUnadvisedExposedInterceptor
* 否则使用DynamicUnadvisedExposedInterceptor。
*
*/
Callback targetInterceptor;
if (exposeProxy) {
targetInterceptor = isStatic ?
new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
}
/*
* 这里的分支逻辑与上面相同,只不过exposeProxy为false的情况下不会设置AopContext中的currentProxy。
*/
else {
targetInterceptor = isStatic ?
new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
} Callback targetDispatcher = isStatic ?
new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp(); Callback[] mainCallbacks = new Callback[] {
// AOP拦截器。
aopInterceptor,
targetInterceptor,
new SerializableNoOp(),
targetDispatcher, this.advisedDispatcher,
new EqualsInterceptor(this.advised),
new HashCodeInterceptor(this.advised)
}; Callback[] callbacks; /*
* 如果targetSource为静态并且配置已经冻结(advice不会改变),可以封装到FixedChainStaticTargetInterceptor来拦截调用方法。
* 其实FixedChainStaticTargetInterceptor里的逻辑就相当于对固定的target每次创建CglibMethodInvocation来实现aop拦截。
*/
if (isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length); for (int x = 0; x < methods.length; x++) {
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
this.fixedInterceptorMap.put(methods[x].toString(), x);
} // 把mainCallbacks和fixedCallbacks拼起来。
callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
this.fixedInterceptorOffset = mainCallbacks.length;
}
else {
callbacks = mainCallbacks;
}
return callbacks;
}

4.2.2 CglibAopProxy的CallbackFilter

我们这里主要看ProxyCallbackFilter#accept方法的源码实现。

public int accept(Method method) {
// finalize方法使用SerializableNoOp
if (AopUtils.isFinalizeMethod(method)) {
logger.debug("Found finalize() method - using NO_OVERRIDE");
return NO_OVERRIDE;
}
if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
if (logger.isDebugEnabled()) {
logger.debug("Method is declared on Advised interface: " + method);
}
return DISPATCH_ADVISED;
}
// equals方法使用EqualsInterceptor。
if (AopUtils.isEqualsMethod(method)) {
logger.debug("Found 'equals' method: " + method);
return INVOKE_EQUALS;
}
// hashCode方法使用HashCodeInterceptor。
if (AopUtils.isHashCodeMethod(method)) {
logger.debug("Found 'hashCode' method: " + method);
return INVOKE_HASHCODE;
}
Class<?> targetClass = this.advised.getTargetClass();
List<?> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
boolean haveAdvice = !chain.isEmpty();
boolean exposeProxy = this.advised.isExposeProxy();
boolean isStatic = this.advised.getTargetSource().isStatic();
boolean isFrozen = this.advised.isFrozen();
if (haveAdvice || !isFrozen) {
// 有advice,配置没有冻结,且需要暴露proxy,使用DynamicAdvisedInterceptor。
if (exposeProxy) {
if (logger.isDebugEnabled()) {
logger.debug("Must expose proxy on advised method: " + method);
}
return AOP_PROXY;
}
String key = method.toString();
// 如果满足优化条件(targetSource静态且配置冻结),则尝试使用fixedInterceptor。
if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(key)) {
if (logger.isDebugEnabled()) {
logger.debug("Method has advice and optimisations are enabled: " + method);
}
// 从fixedInterceptorMap中拿到编号加上偏移量即可。
int index = this.fixedInterceptorMap.get(key);
return (index + this.fixedInterceptorOffset);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Unable to apply any optimisations to advised method: " + method);
}
return AOP_PROXY;
}
}
else {
/*
* 如果需要暴露proxy或者targetSource非静态,则使用的callback可能是下面三种之一。
* StaticUnadvisedExposedInterceptor
* DynamicUnadvisedExposedInterceptor
* DynamicUnadvisedInterceptor
*/
if (exposeProxy || !isStatic) {
return INVOKE_TARGET;
}
Class<?> returnType = method.getReturnType();
// 返回的类型与targetClass一致(有可能返回this),使用StaticUnadvisedInterceptor。
if (targetClass == returnType) {
if (logger.isDebugEnabled()) {
logger.debug("Method " + method +
"has return type same as target type (may return this) - using INVOKE_TARGET");
}
return INVOKE_TARGET;
}
// 返回类型为基本类型或者targetClass不兼容于返回类型(不可能返回this),使用StaticDispatcher。
else if (returnType.isPrimitive() || !returnType.isAssignableFrom(targetClass)) {
if (logger.isDebugEnabled()) {
logger.debug("Method " + method +
" has return type that ensures this cannot be returned- using DISPATCH_TARGET");
}
return DISPATCH_TARGET;
}
else {
// 这种情况targetClass是返回类型的子类(可能返回this),使用StaticUnadvisedInterceptor。
if (logger.isDebugEnabled()) {
logger.debug("Method " + method +
"has return type that is assignable from the target type (may return this) - " +
"using INVOKE_TARGET");
}
return INVOKE_TARGET;
}
}
}

4.2.3 CglibAopProxy的AOP方法拦截器--DynamicAdvisedInterceptor

在spring中通过cglib创建的代理中,对于需要增强的方法设置的callback为DynamicAdvisedInterceptor,它实现了cglib的MethodInterceptor。

private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

    private final AdvisedSupport advised;

    public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
} @Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 拿出原始bean对象。
target = getTarget();
if (target != null) {
targetClass = target.getClass();
} // 根据method和class从配置中获取增强。
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// 如果没有增强并且方法为public,则直接调用。
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// 创建拦截器链并调用。
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
} @Override
public boolean equals(Object other) {
return (this == other ||
(other instanceof DynamicAdvisedInterceptor &&
this.advised.equals(((DynamicAdvisedInterceptor) other).advised)));
} @Override
public int hashCode() {
return this.advised.hashCode();
} protected Object getTarget() throws Exception {
return this.advised.getTargetSource().getTarget();
} protected void releaseTarget(Object target) throws Exception {
this.advised.getTargetSource().releaseTarget(target);
}
}

4.3 ReflectiveMethodInvocation#proceed

这里来看一下方法拦截器的具体实现。这个类特别重要,它是JDK动态代理和cglib代理底层都会用到的类,也就是作用在方法上的增强链的本质。

public Object proceed() throws Throwable {
// 边界判断,如果拦截器都调用完毕了就调用连接点方法。
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
} // 迭代拦截器联获取当前的拦截器。
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
// 判断是否和当前的切点匹配。
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// 如果不匹配的话,就递归调用proceed。
return proceed();
}
}
else {
// 如果是一个MethodInterceptor的话则直接调用。
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}

5. 思考

为什么cglib创建的代理方法内部互相调用不会进入代理

这是个很常见的问题,比如会有疑问为什么一个非事务方法调用事务方法没有进入事务等等。下面通过源码来分析原因。

通过查看源码可以看到,Spring的cglib的AOP无论方法是否有增强,本质上都是对target进行调用。这里的target对于一般的AOP通常都是来源于



AbstractAutoProxyCreator#wrapIfNecessary中通过SingletonTargetSource包装的入参bean,而不是cglib中实际生成的proxy对象。也就是说很可能target就是一个很朴素的bean。那么进入到这样一个bean中的方法自然不会再触发cglib代理的callback拦截了。

其实可以将代理看作是一个外壳,在方法被调用的时候会被拦截进入到壳子中写好的逻辑,但是方法体本身已经脱离了外壳层,是在本体中运行的。

拦截器的顺序问题

这个问题也是经常会困扰的问题,就是关于那些各种aop切方法,到底哪个会先切,哪个后切。

AbstractAutoProxyCreator#wrapIfNecessary中getAdvicesAndAdvisorsForBean用来抓取advice和advisor。

我们以AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean的实现为例:



注意到这其中是有排序的逻辑的,以AspectJAwareAdvisorAutoProxyCreator#sortAdvisors为例可以看到用的comparator是内置的默认比较器AspectJPrecedenceComparator。

不妨再看一下AspectJPrecedenceComparator的比较策略:



可以看到会先使用内部的AnnotationAwareOrderComparator来比较,如果优先级相同,则再调用comparePrecedenceWithinAspect进行比较。

AnnotationAwareOrderComparator继承自OrderComparator, 在OrderComparator中的判断顺序逻辑是如果任一对象是PriorityOrder接口的子类型,则具有更高优先级。否则调用getOrder方法比较。

注意,上面的排序规则只是影响了各advice的调用顺序,并不代表我们关注的aop实际逻辑的调用顺序,比如AspectJAfterAdvice#invoke也是先对methodInvocation调用proceed再处理本身的后置逻辑。

Spring AOP的实现研究的更多相关文章

  1. 按照自己的思路去研究Spring AOP源码【1】

    目录 一个例子 Spring AOP 原理 从@EnableAspectJAutoProxy注解入手 什么时候会创建代理对象? 方法执行时怎么实现拦截的? 总结 问题 参考 一个例子 // 定义一个切 ...

  2. 按照自己的思路研究Spring AOP源码【2】

    目录 问题的提出 哪一步导致了顺序的改变 AbstractAdvisorAutoProxyCreator.sortAdvisors()方法 总结 问题的提出 上面这篇文章介绍了Spring AOP源码 ...

  3. 学习AOP之认识一下Spring AOP

    心碎之事 要说知道AOP这个词倒是很久很久以前了,但是直到今天我也不敢说非常的理解它,其中的各种概念即抽象又太拗口. 在几次面试中都被问及AOP,但是真的没有答上来,或者都在面上,这给面试官的感觉就是 ...

  4. 从零开始学 Java - Spring AOP 实现主从读写分离

    深刻讨论为什么要读写分离? 为了服务器承载更多的用户?提升了网站的响应速度?分摊数据库服务器的压力?就是为了双机热备又不想浪费备份服务器?上面这些回答,我认为都不是错误的,但也都不是完全正确的.「读写 ...

  5. java框架篇---spring AOP 实现原理

    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入 ...

  6. Spring aop的实现原理

    简介 前段时间写的java设计模式--代理模式,最近在看Spring Aop的时候,觉得于代理模式应该有密切的联系,于是决定了解下Spring Aop的实现原理. 说起AOP就不得不说下OOP了,OO ...

  7. Spring AOP 系列总括

    Spring有两大核心,IOC和AOP.IOC在Java Web项目中无时无刻不在使用,然而AOP用的比较少,尤其是对一些初级程序员,在架构师搭好的框架上开发应用代码,AOP几乎是透明的.然而,项目中 ...

  8. Spring AOP 详解

    AOP使用场景 AOP用来封装横切关注点,具体可以在下面的场景中使用: Authentication 权限 Caching 缓存 Context passing 内容传递 Error handling ...

  9. 转:Spring AOP术语

    1.连接点(Joinpoint)       程序执行的某个特定位置:如类开始初始化前.类初始化后.类某个方法调用前.调用后.方法抛出异常后.这些代码中的特定点,称为“连接点”.Spring仅支持方法 ...

随机推荐

  1. myeclipse 添加mybatis generator插件

    在红色的方框中输入下面的网址,一直下一步,最后finish即可. https://dl.bintray.com/mybatis/mybatis-generator/

  2. Django之破解数独

      数独是一项快乐的益智游戏,起源于18世纪瑞士的一种数学游戏.解答者需要运用纸.笔进行演算,需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行.每一列.每一个粗线宫(3*3)内的 ...

  3. Umbraco 资源推荐

    Umbraco 社区 Umbraco 官方社区.找到人们谈论当前的 Umbraco 主题的最好方法是通过 Twitter.Umbraco 也知道他们很多的聚会和节日在世界各地举行.Umbraco 的开 ...

  4. 【WebSocket No.2】WebSocket和Socket实现聊天群发

    介绍: 前面写过一篇简单的websocke实现服务端.这一篇就不在说什么基础的东西主要是来用实例说话,主要是讲一下实现单聊和群组聊天和所有群发的思路设计. 直接不懂的可以看一下上一篇简单版本再来看也行 ...

  5. [android] 手机卫士自定义组合控件

    设置中心 新建SettingActivity 设置GridView条目的点击事件 调用GridView对象的setOnItemClickListenner()方法,参数:OnItemClickList ...

  6. Java并发编程:ThreadLocal的使用以及实现原理解析

    前言 前面的文章里,我们学习了有关锁的使用,锁的机制是保证同一时刻只能有一个线程访问临界区的资源,也就是通过控制资源的手段来保证线程安全,这固然是一种有效的手段,但程序的运行效率也因此大大降低.那么, ...

  7. Cylinder Candy(积分)

    Cylinder Candy Time Limit: 2 Seconds Memory Limit: 65536 KB Special Judge Edward the confectioner is ...

  8. c++类构造函数详解

    //一. 构造函数是干什么的 /*   类对象被创建时,编译系统对象分配内存空间,并自动调用该构造函数->由构造函数完成成员的初始化工作      eg: Counter c1;      编译 ...

  9. 微信服务号获取openid方法

    public function tetst(){ if(!isset($_GET['code'])){ $APPID = $this->app_id; $ran = rand(1,100); / ...

  10. nginx 匹配规则小总结

    nginx location 等号类型(=)的优先级最高,需要精确匹配.一旦匹配成功,则不再查找其他匹配项. ^~类型表达式.一旦匹配成功,则不再查找其他匹配项. 正则表达式类型(~ ~*)的优先级次 ...