对Spring平台或者说生态系统来说,AOP是Spring框架的核心功能模块之一。AOP与IOC容器的结合使用, 为应用开发或者Spring自身功能的扩展都提供了许多便利。Spring AOP的实现和其他特性的实现一样,非常丰富,除了可以使用Spring本身提供的AOP实现之外,还封装了业界优秀的AOP解决方案AspectJ来让应用使用。在这里,主要对Spring自身的AOP实现原理做一些解析;在这个AOP实现中,Spring充分利用了IOC容器Proxy代理对象以及AOP拦截器的功能特性,通过这些对AOP基本功能的封装机制,为用户提供了AOP的实现框架。所以,要了解这些AOP的基本实现,需要我们对Java 的Proxy机制有一些基本了解。
AOP实现的基本线索
AOP实现中,可以看到三个主要的步骤,一个是代理对象的生成,然后是拦截器的作用,然后是Aspect编织的实现。AOP框架的丰富,很大程度体现在这三个具体实现中,所具有的丰富的技术选择,以及如何实现与IOC容器的无缝结合。毕竟这也是一个非常核心的模块,需要满足不同的应用需求带来的解决方案需求。
在Spring AOP的实现原理中,我们主要举ProxyFactoryBean(aspectj方案则是AspectJProxyFactory)的实现作为例子和实现的基本线索进行分析;很大一个原因,是因为ProxyFactoryBean是在Spring IoC环境中,创建AOP应用的最底层方法,从中,可以看到一条实现AOP的基本线索。在ProxyFactoryBean中,它的AOP实现需要依赖JDK或者CGLIB提供的Proxy特性。从FactoryBean中获取对象,是从getObject()方法作为入口完成的。然后为proxy代理对象配置advisor链,这个配置是在initializeAdvisorChain方法中完成的,这样就为生成AOP代理对象做好了准备。代码如下;
ProxyFactoryBean
- public Object getObject() throws BeansException {
- initializeAdvisorChain();
- if (isSingleton()) {
- return getSingletonInstance();
- }
- else {
- if (this.targetName == null) {
- logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
- "Enable prototype proxies by setting the 'targetName' property.");
- }
- return newPrototypeInstance();
- }
- }
ProxyCreatorSupport
- protected final synchronized AopProxy createAopProxy() {
- if (!this.active) {
- activate();
- }
- return getAopProxyFactory().createAopProxy(this);
- }
DefaultAopProxyFactory
- 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()) {
- return new JdkDynamicAopProxy(config);
- }
- return CglibProxyFactory.createCglibProxy(config);
- }
- else {
- return new JdkDynamicAopProxy(config);
- }
- }
我们回忆一下我们做过的jdk代理的例子:
- UserMgr mgr = new UserMgrImpl();
- InvocationHandler h = new TransactionHandler(mgr);
- UserMgr u = (UserMgr) Proxy.newProxyInstance(UserMgr.class, h);
生成的代理是比如$Proxy34,h是$Proxy34的成员变量,
- public class Proxy implements java.io.Serializable {
- /** prefix for all proxy class names */
- private final static String proxyClassNamePrefix = "$Proxy";
- /**
- * the invocation handler for this proxy instance.
- * @serial
- */
- protected InvocationHandler h;
- }
在spring aop中正是JdkDynamicAopProxy。那么重点来了,我们就从JdkDynamicAopProxy的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;
- Class<?> targetClass = null;
- Object target = null;
- try {
- if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
- // The target does not implement the equals(Object) method itself.
- return equals(args[0]);
- }
- if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
- // The target does not implement the hashCode() method itself.
- return hashCode();
- }
- 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;
- }
- // May be null. Get as late as possible to minimize the time we "own" the target,
- // in case it comes from a pool.
- target = targetSource.getTarget();
- if (target != null) {
- targetClass = target.getClass();
- }
- // 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.
- retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
- }
- else {
- // We need to create a method invocation...
- 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.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 implements ProxyMethodInvocation extends MethodInvocation extends Invocation extends Joinpoint
- 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;
- if (dm.methodMatcher.matches(this.method, this.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 { // eg. <span style="line-height: 25.2px; white-space: normal;">ExposeInvocationInterceptor</span>
- // 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);
- }
- }
- package org.aopalliance.intercept; // Aop联盟
- import java.lang.reflect.AccessibleObject;
- public interface Joinpoint {
- Object proceed() throws Throwable;
- Object getThis();
- AccessibleObject getStaticPart();
- }
interceptor.invoker - eg. MethodBeforeAdviceInterceptor
- public Object invoke(MethodInvocation mi) throws Throwable {
- this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
- return mi.proceed(); // 又回归到了上面的调用
- }
值得注意的是,虽然切面可以只用到一个类的部分方法上,但我们调用其他方法时,仍然会经历上面的逻辑,此时拦截器链里只有一个interceptor - ExposeInvocationInterceptor
- public Object invoke(MethodInvocation mi) throws Throwable {
- MethodInvocation oldInvocation = invocation.get();
- invocation.set(mi);
- try {
- return mi.proceed();
- }
- finally {
- invocation.set(oldInvocation);
- }
- }
Aop应用参考:
一、分库分表http://wely.iteye.com/blog/2275725
二、方法性能监控
- package com.itlong.bjxizhan.support.web.service.monitor;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.annotation.Around;
- import org.aspectj.lang.annotation.Aspect;
- /**
- * Created by shenhongxi on 2016/8/10.
- */
- @Aspect
- public class MonitorAspect {
- private String tagPrefix;
- @Around(
- value = "execution(* *(..)) && @annotation(monitor)",
- argNames = "pjp,monitor"
- )
- public Object doUmpLogging(ProceedingJoinPoint pjp, Monitor monitor) throws Throwable {
- // String tag = monitor.tag();
- // boolean heart = monitor.heart();
- long start = System.currentTimeMillis();
- // record invocation (times)
- Object obj = null;
- try {
- obj = pjp.proceed();
- } catch (Exception e) {
- // record error
- throw e;
- } finally {
- long end = System.currentTimeMillis();
- // record time -> end - start
- }
- return obj;
- }
- public String getTagPrefix() {
- return tagPrefix;
- }
- public void setTagPrefix(String tagPrefix) {
- this.tagPrefix = tagPrefix;
- }
- }
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
- public @interface Monitor {
- String DEFAULT_TAG_NAME = "@@USE_METHOD_NAME";
- String tag() default "@@USE_METHOD_NAME";
- String message() default "";
- boolean heart() default false;
- }
另外,性能监控拦截器可参考org.springframework.aop.interceptor.PerformanceMonitorInterceptor
原文链接:[http://wely.iteye.com/blog/2313924]