博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring aop源码实现分析
阅读量:6511 次
发布时间:2019-06-24

本文共 10533 字,大约阅读时间需要 35 分钟。

AOP就是面向切面编程,我们可以从几个层面来实现AOP。

在编译器修改源代码,在运行期字节码加载前修改字节码或字节码加载后动态创建代理类的字节码,以下是各种实现机制的比较。
spring AOP是Spring框架面向切面的编程思想,AOP采用一种称为“横切”的技术,将涉及多业务流程的通用功能抽取并单独封装,形成独立的切面,在合适的时机将这些切面横向切入到业务流程指定的位置中。 AOP到底能做什么呢? AOP能做的事情非常多。

  • 性能监控,在方法调用前后记录调用时间,方法执行太长或超时报警。
  • 缓存代理,缓存某方法的返回值,下次执行该方法时,直接从缓存里获取。
  • 软件破解,使用AOP修改软件的验证类的判断逻辑。
  • 记录日志,在方法执行前后记录系统日志。
  • 工作流系统,工作流系统需要将业务代码和流程引擎代码混合在一起执行,那么我们可以使用AOP将其分离,并动态挂接业务。
  • 权限验证,方法执行前验证是否有权限执行当前方法,没有则抛出没有权限执行异常,由业务代码捕捉。

本篇将结合动态代理的源代码讲解其实现原理:

1. 先分析Advice

before执行Cglib2AopProxy的intercept方法:

/**     * General purpose AOP callback. Used when the target is dynamic or when the     * proxy is not frozen.     */    private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {        private AdvisedSupport advised;        public DynamicAdvisedInterceptor(AdvisedSupport advised) {            this.advised = advised;        }        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {            MethodInvocation invocation = null;            Object oldProxy = null;            boolean setProxyContext = false;            Class targetClass = null;            Object target = null;            try {                Object retVal = null;                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 = getTarget();                if (target != null) {                    targetClass = target.getClass();                }                List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);                // 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.                    retVal = methodProxy.invoke(target, args);                }                else {                    // We need to create a method invocation...                    invocation = new CglibMethodInvocation(proxy, target, method, args,                            targetClass, chain, methodProxy);                    // If we get here, we need to create a MethodInvocation.                    retVal = invocation.proceed();                }                retVal = massageReturnTypeIfNecessary(proxy, target, method, retVal);                return retVal;            }            finally {                if (target != null) {                    releaseTarget(target);                }                if (setProxyContext) {                    // Restore old proxy.                    AopContext.setCurrentProxy(oldProxy);                }            }        }复制代码

第一步:获取target

target.getClass();

第二步:获取拦截器和advice,返回定义好的

org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor示例

/**     * Determine a list of {@link org.aopalliance.intercept.MethodInterceptor} objects     * for the given method, based on this configuration.     * @param method the proxied method     * @param targetClass the target class     * @return List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)     */    public List getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {        MethodCacheKey cacheKey = new MethodCacheKey(method);        List cached = (List) this.methodCache.get(cacheKey);        if (cached == null) {            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(                    this, method, targetClass);            this.methodCache.put(cacheKey, cached);        }        return cached;    }复制代码

第三步创建一个方法的invocation

// We need to create a method invocation...                    invocation = new CglibMethodInvocation(proxy, target, method, args,                            targetClass, chain, methodProxy);复制代码

第四步 执行aop的before方法

public void before(Method method, Object[] args, Object target)            throws Throwable {        System.out.println(" Before method!");    }复制代码

第五步 触发MethodBeforeAdviceInterceptor的invoke方法

public Object invoke(MethodInvocation mi) throws Throwable {        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );        return mi.proceed();    }复制代码

第六步:触发ReflectiveMethodInvocation的process方法

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 {            // 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);        }    }复制代码

第七步,包装返回值Cglib2AopProxy

/**     * Wrap a return of this if necessary to be the proxy     */    private static Object massageReturnTypeIfNecessary(Object proxy, Object target, Method method, Object retVal) {        // Massage return value if necessary        if (retVal != null && retVal == target &&                !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {            // Special case: it returned "this".            // Note that we can't help if the target sets a reference            // to itself in another returned object.            retVal = proxy;        }        return retVal;    }复制代码

最后执行finanly方法

finally {                if (target != null) {                    releaseTarget(target);                }                if (setProxyContext) {                    // Restore old proxy.                    AopContext.setCurrentProxy(oldProxy);                }复制代码

before,after,around,throw基本相似,不一一赘述

2.PointCut和Advisor为例

2.1 创建代理的过程

首先是ProxyFactoryBean获取对象代理

/**     * Return a proxy. Invoked when clients obtain beans from this factory bean.     * Create an instance of the AOP proxy to be returned by this factory.     * The instance will be cached for a singleton, and create on each call to     * getObject() for a proxy.     * @return a fresh AOP proxy reflecting the current state of this factory     */    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();        }    }复制代码

获取过程如下:

/**     * Return the singleton instance of this class's proxy object,     * lazily creating it if it hasn't been created already.     * @return the shared singleton proxy     */    private synchronized Object getSingletonInstance() {        if (this.singletonInstance == null) {            this.targetSource = freshTargetSource();            if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {                // Rely on AOP infrastructure to tell us what interfaces to proxy.                Class targetClass = getTargetClass();                if (targetClass == null) {                    throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");                }                setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));            }            // Initialize the shared singleton instance.            super.setFrozen(this.freezeProxy);            this.singletonInstance = getProxy(createAopProxy());        }        return this.singletonInstance;    } 复制代码

父类创建代理的过程

/**     * Subclasses should call this to get a new AOP proxy. They should not     * create an AOP proxy with this as an argument.     */    protected final synchronized AopProxy createAopProxy() {        if (!this.active) {            activate();        }        return getAopProxyFactory().createAopProxy(this);    }复制代码

调用代理工厂创建代理的过程

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);            }            if (!cglibAvailable) {                throw new AopConfigException(                        "Cannot proxy target class because CGLIB2 is not available. " +                        "Add CGLIB to the class path or specify proxy interfaces.");            }            return CglibProxyFactory.createCglibProxy(config);        }        else {            return new JdkDynamicAopProxy(config);        }    }复制代码

转载地址:http://czcfo.baihongyu.com/

你可能感兴趣的文章
Mysql用户密码设置修改和权限分配
查看>>
安装centos7
查看>>
DB Commit Time
查看>>
第一课 PHP学习要求
查看>>
postfix相关问题整理及处理
查看>>
Linux Redhat系统的三种包的使用
查看>>
修改mysql的监听地址(unknown variable ‘defaults-file) 10 Apr, 2008 mysql
查看>>
实用的网站
查看>>
nginx服务器安装设置全部知识
查看>>
快捷方式的小箭头
查看>>
表字段部分更新
查看>>
“ABC”时代,IT变革下的驱动数据价值之路
查看>>
每日一shell(八)nginx日志切割
查看>>
无法回应的ARP请求包导致的网站缓慢问题排错
查看>>
软件需求间谍
查看>>
struts2+jquery+json集成
查看>>
一个得到内存信息的shell以及遇到的一个坑
查看>>
Reboot/halt/shutdown command on CentOS 7
查看>>
OpenAI最新成果:无监督情绪神经元(水军面临失业威胁……)
查看>>
关于extmail邮件服务器安装extsuite-webman出现的报错
查看>>