zoukankan      html  css  js  c++  java
  • 深入理解SpringAOP之代理对象

      本篇文章主要带大家简单分析一下AOP的代理对象,至于AOP是什么,如何配置等基础性知识,不在这里讨论。阅读前请先参考:代理模式,在这之前我们需要了解springframework的三个核心接口与getBean方法

    一、FactoryBean&BeanFactory&ObjectFactory

      这三个接口都为Springframework的核心接口,虽然这三个名字很像,但是意义却千差万别。面试的时候也常问它们之间的区别。BeanFactory本身就是一个bean的工厂,同时也是我们的IOC容器,而FactoryBean是一个特殊的Bean,我们可以来看看这个接口:

    /*
     * Copyright 2002-2016 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.beans.factory;
    
    import org.springframework.lang.Nullable;
    
    /**
     * Interface to be implemented by objects used within a {@link BeanFactory} which
     * are themselves factories for individual objects. If a bean implements this
     * interface, it is used as a factory for an object to expose, not directly as a
     * bean instance that will be exposed itself.
     *
     * <p><b>NB: A bean that implements this interface cannot be used as a normal bean.</b>
     * A FactoryBean is defined in a bean style, but the object exposed for bean
     * references ({@link #getObject()}) is always the object that it creates.
     *
     * <p>FactoryBeans can support singletons and prototypes, and can either create
     * objects lazily on demand or eagerly on startup. The {@link SmartFactoryBean}
     * interface allows for exposing more fine-grained behavioral metadata.
     *
     * <p>This interface is heavily used within the framework itself, for example for
     * the AOP {@link org.springframework.aop.framework.ProxyFactoryBean} or the
     * {@link org.springframework.jndi.JndiObjectFactoryBean}. It can be used for
     * custom components as well; however, this is only common for infrastructure code.
     *
     * <p><b>{@code FactoryBean} is a programmatic contract. Implementations are not
     * supposed to rely on annotation-driven injection or other reflective facilities.</b>
     * {@link #getObjectType()} {@link #getObject()} invocations may arrive early in
     * the bootstrap process, even ahead of any post-processor setup. If you need access
     * other beans, implement {@link BeanFactoryAware} and obtain them programmatically.
     *
     * <p>Finally, FactoryBean objects participate in the containing BeanFactory's
     * synchronization of bean creation. There is usually no need for internal
     * synchronization other than for purposes of lazy initialization within the
     * FactoryBean itself (or the like).
     *
     * @author Rod Johnson
     * @author Juergen Hoeller
     * @since 08.03.2003
     * @see org.springframework.beans.factory.BeanFactory
     * @see org.springframework.aop.framework.ProxyFactoryBean
     * @see org.springframework.jndi.JndiObjectFactoryBean
     */
    public interface FactoryBean<T> {
    
        /**
         * Return an instance (possibly shared or independent) of the object
         * managed by this factory.
         * <p>As with a {@link BeanFactory}, this allows support for both the
         * Singleton and Prototype design pattern.
         * <p>If this FactoryBean is not fully initialized yet at the time of
         * the call (for example because it is involved in a circular reference),
         * throw a corresponding {@link FactoryBeanNotInitializedException}.
         * <p>As of Spring 2.0, FactoryBeans are allowed to return {@code null}
         * objects. The factory will consider this as normal value to be used; it
         * will not throw a FactoryBeanNotInitializedException in this case anymore.
         * FactoryBean implementations are encouraged to throw
         * FactoryBeanNotInitializedException themselves now, as appropriate.
         * @return an instance of the bean (can be {@code null})
         * @throws Exception in case of creation errors
         * @see FactoryBeanNotInitializedException
         */
        @Nullable
        T getObject() throws Exception;
    
        /**
         * Return the type of object that this FactoryBean creates,
         * or {@code null} if not known in advance.
         * <p>This allows one to check for specific types of beans without
         * instantiating objects, for example on autowiring.
         * <p>In the case of implementations that are creating a singleton object,
         * this method should try to avoid singleton creation as far as possible;
         * it should rather estimate the type in advance.
         * For prototypes, returning a meaningful type here is advisable too.
         * <p>This method can be called <i>before</i> this FactoryBean has
         * been fully initialized. It must not rely on state created during
         * initialization; of course, it can still use such state if available.
         * <p><b>NOTE:</b> Autowiring will simply ignore FactoryBeans that return
         * {@code null} here. Therefore it is highly recommended to implement
         * this method properly, using the current state of the FactoryBean.
         * @return the type of object that this FactoryBean creates,
         * or {@code null} if not known at the time of the call
         * @see ListableBeanFactory#getBeansOfType
         */
        @Nullable
        Class<?> getObjectType();
    
        /**
         * Is the object managed by this factory a singleton? That is,
         * will {@link #getObject()} always return the same object
         * (a reference that can be cached)?
         * <p><b>NOTE:</b> If a FactoryBean indicates to hold a singleton object,
         * the object returned from {@code getObject()} might get cached
         * by the owning BeanFactory. Hence, do not return {@code true}
         * unless the FactoryBean always exposes the same reference.
         * <p>The singleton status of the FactoryBean itself will generally
         * be provided by the owning BeanFactory; usually, it has to be
         * defined as singleton there.
         * <p><b>NOTE:</b> This method returning {@code false} does not
         * necessarily indicate that returned objects are independent instances.
         * An implementation of the extended {@link SmartFactoryBean} interface
         * may explicitly indicate independent instances through its
         * {@link SmartFactoryBean#isPrototype()} method. Plain {@link FactoryBean}
         * implementations which do not implement this extended interface are
         * simply assumed to always return independent instances if the
         * {@code isSingleton()} implementation returns {@code false}.
         * <p>The default implementation returns {@code true}, since a
         * {@code FactoryBean} typically manages a singleton instance.
         * @return whether the exposed object is a singleton
         * @see #getObject()
         * @see SmartFactoryBean#isPrototype()
         */
        default boolean isSingleton() {
            return true;
        }
    
    }
    View Code

      这里面有三个方法,分别为:getObject,getObjectType,isSingleton。根据文档解释,它只是一个生产对象的工厂,被Spring管理 。这个工厂负责提供我们需要的对象。当需要特殊的方式创建Bean时,则考虑实现该接口。我举个例子来说明:

    package org.hzgj.spring.study;
    
    import org.springframework.beans.factory.FactoryBean;
    import org.springframework.stereotype.Component;
    
    @Component
    public class WaterFactoryBean implements FactoryBean<Water> {
    
        @Override
        public Water getObject() throws Exception {
            Water water=new Water();
            water.setCapacity(20);
            return water;
        }
    
        @Override
        public Class<?> getObjectType() {
            return Water.class;
        }
    
        @Override
        public boolean isSingleton() {
            return true;
        }
    }
    
    //.....
    
    package org.hzgj.spring.study;
    
    @Deprecated
    public class Water {
    
        private int capacity;
    
        public int getCapacity() {
            return capacity;
        }
    
        public void setCapacity(int capacity) {
            this.capacity = capacity;
        }
    
        public void test() {
            System.out.println("test");
        }
    
        @Deprecated
        public void test1() {
            System.out.println("test1");
        }
    }
    //.....
    
      ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");
            Water water = applicationContext.getBean(Water.class);
            water.test1();
    // ....能够成功获取到对象

      在上面例子里,我们本身是要获得Water对象,那么此时Water对象实际上是通过FactoryBean创建的,因此我们在获取对象时可以添加我们自己的逻辑。

      下面我们根据源代码来追溯一下getBean与BeanFactory关联,具体可以参考一下AbstractBeanFactory的doGetBean方法,那么在这里简单的说明一下执行过程:

      1) 如果是单例对象的Bean会去缓存中获取

        我们先看一下getSinglelone方法:

    /** Cache of singleton objects: bean name --> bean instance */
        private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
    
    
    /** Cache of singleton factories: bean name --> ObjectFactory */
        private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
    
    /** Cache of early singleton objects: bean name --> bean instance */
        private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
    
    
    /**
         * Return the (raw) singleton object registered under the given name.
         * <p>Checks already instantiated singletons and also allows for an early
         * reference to a currently created singleton (resolving a circular reference).
         * @param beanName the name of the bean to look for
         * @param allowEarlyReference whether early references should be created or not
         * @return the registered singleton object, or {@code null} if none found
         */
        protected Object getSingleton(String beanName, boolean allowEarlyReference) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
                synchronized (this.singletonObjects) {
                    singletonObject = this.earlySingletonObjects.get(beanName);
                    if (singletonObject == null && allowEarlyReference) {
                        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                        if (singletonFactory != null) {
                            singletonObject = singletonFactory.getObject();
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            this.singletonFactories.remove(beanName);
                        }
                    }
                }
            }
            return (singletonObject != NULL_OBJECT ? singletonObject : null);
        }

        在这里我们获取单例对象时一定和ObjectFactory有关系

      2)从它的parentBeanFactory中获取

    // Check if bean definition exists in this factory.
                BeanFactory parentBeanFactory = getParentBeanFactory();
                if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                    // Not found -> check parent.
                    String nameToLookup = originalBeanName(name);
                    if (args != null) {
                        // Delegation to parent with explicit args.
                        return (T) parentBeanFactory.getBean(nameToLookup, args);
                    }
                    else {
                        // No args -> delegate to standard getBean method.
                        return parentBeanFactory.getBean(nameToLookup, requiredType);
                    }
                }

      3)处理bean的dependsOn

    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                    checkMergedBeanDefinition(mbd, beanName, args);
    
                    // Guarantee initialization of beans that the current bean depends on.
                    String[] dependsOn = mbd.getDependsOn();
                    if (dependsOn != null) {
                        for (String dep : dependsOn) {
                            if (isDependent(beanName, dep)) {
                                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                            }
                            registerDependentBean(dep, beanName);
                            getBean(dep);
                        }
                    }

      4)根据bean的scope类型来获取对应的bean

        // Create bean instance.
                    if (mbd.isSingleton()) {
                        sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                            @Override
                            public Object getObject() throws BeansException {
                                try {
                                    return createBean(beanName, mbd, args);
                                }
                                catch (BeansException ex) {
                                    // Explicitly remove instance from singleton cache: It might have been put there
                                    // eagerly by the creation process, to allow for circular reference resolution.
                                    // Also remove any beans that received a temporary reference to the bean.
                                    destroySingleton(beanName);
                                    throw ex;
                                }
                            }
                        });
                        bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                    }
    
                    else if (mbd.isPrototype()) {
                        // It's a prototype -> create a new instance.
                        Object prototypeInstance = null;
                        try {
                            beforePrototypeCreation(beanName);
                            prototypeInstance = createBean(beanName, mbd, args);
                        }
                        finally {
                            afterPrototypeCreation(beanName);
                        }
                        bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                    }
    
                    else {
                        String scopeName = mbd.getScope();
                        final Scope scope = this.scopes.get(scopeName);
                        if (scope == null) {
                            throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                        }
                        try {
                            Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                                @Override
                                public Object getObject() throws BeansException {
                                    beforePrototypeCreation(beanName);
                                    try {
                                        return createBean(beanName, mbd, args);
                                    }
                                    finally {
                                        afterPrototypeCreation(beanName);
                                    }
                                }
                            });
                            bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                        }
                        catch (IllegalStateException ex) {
                            throw new BeanCreationException(beanName,
                                    "Scope '" + scopeName + "' is not active for the current thread; consider " +
                                    "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                                    ex);
                        }
                    }
                }
                catch (BeansException ex) {
                    cleanupAfterBeanCreationFailure(beanName);
                    throw ex;
                }
            }

      5)  根据需要做类型转换

    // Check if required type matches the type of the actual bean instance.
            if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
                try {
                    return getTypeConverter().convertIfNecessary(bean, requiredType);
                }
                catch (TypeMismatchException ex) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Failed to convert bean '" + name + "' to required type '" +
                                ClassUtils.getQualifiedName(requiredType) + "'", ex);
                    }
                    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                }
            }

      6)getObjectForBeanInstance

      通过源代码我们可以发觉 getObjectForBeanInstance方法调用频率异常之高,那么我们就来看一看,它到底是做什么的:

    /**
         * Get the object for the given bean instance, either the bean
         * instance itself or its created object in case of a FactoryBean.
         * @param beanInstance the shared bean instance
         * @param name name that may include factory dereference prefix
         * @param beanName the canonical bean name
         * @param mbd the merged bean definition
         * @return the object to expose for the bean
         */
        protected Object getObjectForBeanInstance(
                Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
    
            // Don't let calling code try to dereference the factory if the bean isn't a factory.
            if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
                throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
            }
    
            // Now we have the bean instance, which may be a normal bean or a FactoryBean.
            // If it's a FactoryBean, we use it to create a bean instance, unless the
            // caller actually wants a reference to the factory.
            if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
                return beanInstance;
            }
    
            Object object = null;
            if (mbd == null) {
                object = getCachedObjectForFactoryBean(beanName);
            }
            if (object == null) {
                // Return bean instance from factory.
                FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
                // Caches object obtained from FactoryBean if it is a singleton.
                if (mbd == null && containsBeanDefinition(beanName)) {
                    mbd = getMergedLocalBeanDefinition(beanName);
                }
                boolean synthetic = (mbd != null && mbd.isSynthetic());
                object = getObjectFromFactoryBean(factory, beanName, !synthetic);
            }
            return object;
        }

      这段代码最主要是看看是否需要从FactoryBean获取对象的。

      最后我们在聊聊ObjectFactory:

    public interface ObjectFactory<T> {
    
        /**
         * Return an instance (possibly shared or independent)
         * of the object managed by this factory.
         * @return an instance of the bean (should never be {@code null})
         * @throws BeansException in case of creation errors
         */
        T getObject() throws BeansException;
    
    }

      该接口和FactoryBean很像,根据文档说明其getObject方法的返回值不建议为null,另外我们可以发现Bean为singlone时会大量的使用ObjectFactory处理,代码示例:

    package org.hzgj.spring.study;
    
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.ObjectFactory;
    import org.springframework.stereotype.Component;
    
    @Component
    public class WaterFactory implements ObjectFactory {
        @Override
        public Object getObject() throws BeansException {
            return new Water();
        }
    }
    
    //这样子无法获取water,它只单纯是个工厂

       ObjectFactory更像是一个在BeanFactory通过Bean名称关联的对象,只不过它在运行时确定getObject()方法返回的对象内容,再者它不像BeanFactory一样能够制定Bean的类型

    二、AOP的核心探究

    2.1、核心接口初探

      为什么刚开始要说FactoryBean,因为它的文档注释已经提醒我们去参考ProxyFactoryBean了,ProxyFactoryBean是生成目标对象代理的核心,那么我们在此先看一下类图:

      

      我们可以得知ProxyFactoryBean实现了FactoryBean。

      关于AOP的几个重要的核心接口和类如下:

      ProxyConfig:

    /*
     * Copyright 2002-2012 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.aop.framework;
    
    import java.io.Serializable;
    
    import org.springframework.util.Assert;
    
    /**
     * Convenience superclass for configuration used in creating proxies,
     * to ensure that all proxy creators have consistent properties.
     *
     * @author Rod Johnson
     * @author Juergen Hoeller
     * @see AdvisedSupport
     */
    public class ProxyConfig implements Serializable {
    
        /** use serialVersionUID from Spring 1.2 for interoperability */
        private static final long serialVersionUID = -8409359707199703185L;
    
    
        private boolean proxyTargetClass = false;
    
        private boolean optimize = false;
    
        boolean opaque = false;
    
        boolean exposeProxy = false;
    
        private boolean frozen = false;
    
    
        /**
         * Set whether to proxy the target class directly, instead of just proxying
         * specific interfaces. Default is "false".
         * <p>Set this to "true" to force proxying for the TargetSource's exposed
         * target class. If that target class is an interface, a JDK proxy will be
         * created for the given interface. If that target class is any other class,
         * a CGLIB proxy will be created for the given class.
         * <p>Note: Depending on the configuration of the concrete proxy factory,
         * the proxy-target-class behavior will also be applied if no interfaces
         * have been specified (and no interface autodetection is activated).
         * @see org.springframework.aop.TargetSource#getTargetClass()
         */
        public void setProxyTargetClass(boolean proxyTargetClass) {
            this.proxyTargetClass = proxyTargetClass;
        }
    
        /**
         * Return whether to proxy the target class directly as well as any interfaces.
         */
        public boolean isProxyTargetClass() {
            return this.proxyTargetClass;
        }
    
        /**
         * Set whether proxies should perform aggressive optimizations.
         * The exact meaning of "aggressive optimizations" will differ
         * between proxies, but there is usually some tradeoff.
         * Default is "false".
         * <p>For example, optimization will usually mean that advice changes won't
         * take effect after a proxy has been created. For this reason, optimization
         * is disabled by default. An optimize value of "true" may be ignored
         * if other settings preclude optimization: for example, if "exposeProxy"
         * is set to "true" and that's not compatible with the optimization.
         */
        public void setOptimize(boolean optimize) {
            this.optimize = optimize;
        }
    
        /**
         * Return whether proxies should perform aggressive optimizations.
         */
        public boolean isOptimize() {
            return this.optimize;
        }
    
        /**
         * Set whether proxies created by this configuration should be prevented
         * from being cast to {@link Advised} to query proxy status.
         * <p>Default is "false", meaning that any AOP proxy can be cast to
         * {@link Advised}.
         */
        public void setOpaque(boolean opaque) {
            this.opaque = opaque;
        }
    
        /**
         * Return whether proxies created by this configuration should be
         * prevented from being cast to {@link Advised}.
         */
        public boolean isOpaque() {
            return this.opaque;
        }
    
        /**
         * Set whether the proxy should be exposed by the AOP framework as a
         * ThreadLocal for retrieval via the AopContext class. This is useful
         * if an advised object needs to call another advised method on itself.
         * (If it uses {@code this}, the invocation will not be advised).
         * <p>Default is "false", in order to avoid unnecessary extra interception.
         * This means that no guarantees are provided that AopContext access will
         * work consistently within any method of the advised object.
         */
        public void setExposeProxy(boolean exposeProxy) {
            this.exposeProxy = exposeProxy;
        }
    
        /**
         * Return whether the AOP proxy will expose the AOP proxy for
         * each invocation.
         */
        public boolean isExposeProxy() {
            return this.exposeProxy;
        }
    
        /**
         * Set whether this config should be frozen.
         * <p>When a config is frozen, no advice changes can be made. This is
         * useful for optimization, and useful when we don't want callers to
         * be able to manipulate configuration after casting to Advised.
         */
        public void setFrozen(boolean frozen) {
            this.frozen = frozen;
        }
    
        /**
         * Return whether the config is frozen, and no advice changes can be made.
         */
        public boolean isFrozen() {
            return this.frozen;
        }
    
    
        /**
         * Copy configuration from the other config object.
         * @param other object to copy configuration from
         */
        public void copyFrom(ProxyConfig other) {
            Assert.notNull(other, "Other ProxyConfig object must not be null");
            this.proxyTargetClass = other.proxyTargetClass;
            this.optimize = other.optimize;
            this.exposeProxy = other.exposeProxy;
            this.frozen = other.frozen;
            this.opaque = other.opaque;
        }
    
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("proxyTargetClass=").append(this.proxyTargetClass).append("; ");
            sb.append("optimize=").append(this.optimize).append("; ");
            sb.append("opaque=").append(this.opaque).append("; ");
            sb.append("exposeProxy=").append(this.exposeProxy).append("; ");
            sb.append("frozen=").append(this.frozen);
            return sb.toString();
        }
    
    }
    View Code

      该类定义代理类最基本的代理配置

      Advised:

    /*
     * Copyright 2002-2015 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.aop.framework;
    
    import org.aopalliance.aop.Advice;
    
    import org.springframework.aop.Advisor;
    import org.springframework.aop.TargetClassAware;
    import org.springframework.aop.TargetSource;
    
    /**
     * Interface to be implemented by classes that hold the configuration
     * of a factory of AOP proxies. This configuration includes the
     * Interceptors and other advice, Advisors, and the proxied interfaces.
     *
     * <p>Any AOP proxy obtained from Spring can be cast to this interface to
     * allow manipulation of its AOP advice.
     *
     * @author Rod Johnson
     * @author Juergen Hoeller
     * @since 13.03.2003
     * @see org.springframework.aop.framework.AdvisedSupport
     */
    public interface Advised extends TargetClassAware {
    
        /**
         * Return whether the Advised configuration is frozen,
         * in which case no advice changes can be made.
         */
        boolean isFrozen();
    
        /**
         * Are we proxying the full target class instead of specified interfaces?
         */
        boolean isProxyTargetClass();
    
        /**
         * Return the interfaces proxied by the AOP proxy.
         * <p>Will not include the target class, which may also be proxied.
         */
        Class<?>[] getProxiedInterfaces();
    
        /**
         * Determine whether the given interface is proxied.
         * @param intf the interface to check
         */
        boolean isInterfaceProxied(Class<?> intf);
    
        /**
         * Change the {@code TargetSource} used by this {@code Advised} object.
         * <p>Only works if the configuration isn't {@linkplain #isFrozen frozen}.
         * @param targetSource new TargetSource to use
         */
        void setTargetSource(TargetSource targetSource);
    
        /**
         * Return the {@code TargetSource} used by this {@code Advised} object.
         */
        TargetSource getTargetSource();
    
        /**
         * Set whether the proxy should be exposed by the AOP framework as a
         * {@link ThreadLocal} for retrieval via the {@link AopContext} class.
         * <p>It can be necessary to expose the proxy if an advised object needs
         * to invoke a method on itself with advice applied. Otherwise, if an
         * advised object invokes a method on {@code this}, no advice will be applied.
         * <p>Default is {@code false}, for optimal performance.
         */
        void setExposeProxy(boolean exposeProxy);
    
        /**
         * Return whether the factory should expose the proxy as a {@link ThreadLocal}.
         * <p>It can be necessary to expose the proxy if an advised object needs
         * to invoke a method on itself with advice applied. Otherwise, if an
         * advised object invokes a method on {@code this}, no advice will be applied.
         * <p>Getting the proxy is analogous to an EJB calling {@code getEJBObject()}.
         * @see AopContext
         */
        boolean isExposeProxy();
    
        /**
         * Set whether this proxy configuration is pre-filtered so that it only
         * contains applicable advisors (matching this proxy's target class).
         * <p>Default is "false". Set this to "true" if the advisors have been
         * pre-filtered already, meaning that the ClassFilter check can be skipped
         * when building the actual advisor chain for proxy invocations.
         * @see org.springframework.aop.ClassFilter
         */
        void setPreFiltered(boolean preFiltered);
    
        /**
         * Return whether this proxy configuration is pre-filtered so that it only
         * contains applicable advisors (matching this proxy's target class).
         */
        boolean isPreFiltered();
    
        /**
         * Return the advisors applying to this proxy.
         * @return a list of Advisors applying to this proxy (never {@code null})
         */
        Advisor[] getAdvisors();
    
        /**
         * Add an advisor at the end of the advisor chain.
         * <p>The Advisor may be an {@link org.springframework.aop.IntroductionAdvisor},
         * in which new interfaces will be available when a proxy is next obtained
         * from the relevant factory.
         * @param advisor the advisor to add to the end of the chain
         * @throws AopConfigException in case of invalid advice
         */
        void addAdvisor(Advisor advisor) throws AopConfigException;
    
        /**
         * Add an Advisor at the specified position in the chain.
         * @param advisor the advisor to add at the specified position in the chain
         * @param pos position in chain (0 is head). Must be valid.
         * @throws AopConfigException in case of invalid advice
         */
        void addAdvisor(int pos, Advisor advisor) throws AopConfigException;
    
        /**
         * Remove the given advisor.
         * @param advisor the advisor to remove
         * @return {@code true} if the advisor was removed; {@code false}
         * if the advisor was not found and hence could not be removed
         */
        boolean removeAdvisor(Advisor advisor);
    
        /**
         * Remove the advisor at the given index.
         * @param index index of advisor to remove
         * @throws AopConfigException if the index is invalid
         */
        void removeAdvisor(int index) throws AopConfigException;
    
        /**
         * Return the index (from 0) of the given advisor,
         * or -1 if no such advisor applies to this proxy.
         * <p>The return value of this method can be used to index into the advisors array.
         * @param advisor the advisor to search for
         * @return index from 0 of this advisor, or -1 if there's no such advisor
         */
        int indexOf(Advisor advisor);
    
        /**
         * Replace the given advisor.
         * <p><b>Note:</b> If the advisor is an {@link org.springframework.aop.IntroductionAdvisor}
         * and the replacement is not or implements different interfaces, the proxy will need
         * to be re-obtained or the old interfaces won't be supported and the new interface
         * won't be implemented.
         * @param a the advisor to replace
         * @param b the advisor to replace it with
         * @return whether it was replaced. If the advisor wasn't found in the
         * list of advisors, this method returns {@code false} and does nothing.
         * @throws AopConfigException in case of invalid advice
         */
        boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;
    
        /**
         * Add the given AOP Alliance advice to the tail of the advice (interceptor) chain.
         * <p>This will be wrapped in a DefaultPointcutAdvisor with a pointcut that always
         * applies, and returned from the {@code getAdvisors()} method in this wrapped form.
         * <p>Note that the given advice will apply to all invocations on the proxy,
         * even to the {@code toString()} method! Use appropriate advice implementations
         * or specify appropriate pointcuts to apply to a narrower set of methods.
         * @param advice advice to add to the tail of the chain
         * @throws AopConfigException in case of invalid advice
         * @see #addAdvice(int, Advice)
         * @see org.springframework.aop.support.DefaultPointcutAdvisor
         */
        void addAdvice(Advice advice) throws AopConfigException;
    
        /**
         * Add the given AOP Alliance Advice at the specified position in the advice chain.
         * <p>This will be wrapped in a {@link org.springframework.aop.support.DefaultPointcutAdvisor}
         * with a pointcut that always applies, and returned from the {@link #getAdvisors()}
         * method in this wrapped form.
         * <p>Note: The given advice will apply to all invocations on the proxy,
         * even to the {@code toString()} method! Use appropriate advice implementations
         * or specify appropriate pointcuts to apply to a narrower set of methods.
         * @param pos index from 0 (head)
         * @param advice advice to add at the specified position in the advice chain
         * @throws AopConfigException in case of invalid advice
         */
        void addAdvice(int pos, Advice advice) throws AopConfigException;
    
        /**
         * Remove the Advisor containing the given advice.
         * @param advice the advice to remove
         * @return {@code true} of the advice was found and removed;
         * {@code false} if there was no such advice
         */
        boolean removeAdvice(Advice advice);
    
        /**
         * Return the index (from 0) of the given AOP Alliance Advice,
         * or -1 if no such advice is an advice for this proxy.
         * <p>The return value of this method can be used to index into
         * the advisors array.
         * @param advice AOP Alliance advice to search for
         * @return index from 0 of this advice, or -1 if there's no such advice
         */
        int indexOf(Advice advice);
    
        /**
         * As {@code toString()} will normally be delegated to the target,
         * this returns the equivalent for the AOP proxy.
         * @return a string description of the proxy configuration
         */
        String toProxyConfigString();
    
    }
    View Code

      该接口主要定义了代理类的工厂基本的行为,比如说添加Advisor,添加Advise,删除与替换Adivsor等

      Adivise:

      通知接口,该接口没有方法定义,其常见的子接口有BeforeAdvise,AfterAdvise,MethodInterceptor等

      PointCut:

      切点接口,该接口定义如下:

    /*
     * Copyright 2002-2012 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.aop;
    
    /**
     * Core Spring pointcut abstraction.
     *
     * <p>A pointcut is composed of a {@link ClassFilter} and a {@link MethodMatcher}.
     * Both these basic terms and a Pointcut itself can be combined to build up combinations
     * (e.g. through {@link org.springframework.aop.support.ComposablePointcut}).
     *
     * @author Rod Johnson
     * @see ClassFilter
     * @see MethodMatcher
     * @see org.springframework.aop.support.Pointcuts
     * @see org.springframework.aop.support.ClassFilters
     * @see org.springframework.aop.support.MethodMatchers
     */
    public interface Pointcut {
    
        /**
         * Return the ClassFilter for this pointcut.
         * @return the ClassFilter (never {@code null})
         */
        ClassFilter getClassFilter();
    
        /**
         * Return the MethodMatcher for this pointcut.
         * @return the MethodMatcher (never {@code null})
         */
        MethodMatcher getMethodMatcher();
    
    
        /**
         * Canonical Pointcut instance that always matches.
         */
        Pointcut TRUE = TruePointcut.INSTANCE;
    
    }
    View Code

      Pointcut由ClassFilter和MethodMatcher构成。它通过ClassFilter定位到某些特定类上,通过MethodMatcher定位到某些特定方法上,这样Pointcut就拥有了描述某些类的某些特定方法的能力。

      Advisor:

      代表一般切面,它仅包含一个Advice,我们说过,因为Advice包含了横切代码和连接点的信息,所以Advior本身就是一个简单的切面,只不过它代表的横切的连接点是所有目标类的所有方法,因为这个横切面太宽泛,所以一般不会直接使用。

    2.2、源码分析

      我们先来看看ProxyFactoryBean的相关方法

      getObject方法:

    /**
         * 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
         * {@code getObject()} for a proxy.
         * @return a fresh AOP proxy reflecting the current state of this factory
         */
        @Override
        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();
            }
        }

      这里面我们关注一下getSingletonInstance方法:

    /**
         * 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;
        }

      在这里我们关在关注一下getProxy(AopProxy aopProxy)方法,AopProxy是一个接口:

    /*
     * Copyright 2002-2012 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.aop.framework;
    
    /**
     * Delegate interface for a configured AOP proxy, allowing for the creation
     * of actual proxy objects.
     *
     * <p>Out-of-the-box implementations are available for JDK dynamic proxies
     * and for CGLIB proxies, as applied by {@link DefaultAopProxyFactory}.
     *
     * @author Rod Johnson
     * @author Juergen Hoeller
     * @see DefaultAopProxyFactory
     */
    public interface AopProxy {
    
        /**
         * Create a new proxy object.
         * <p>Uses the AopProxy's default class loader (if necessary for proxy creation):
         * usually, the thread context class loader.
         * @return the new proxy object (never {@code null})
         * @see Thread#getContextClassLoader()
         */
        Object getProxy();
    
        /**
         * Create a new proxy object.
         * <p>Uses the given class loader (if necessary for proxy creation).
         * {@code null} will simply be passed down and thus lead to the low-level
         * proxy facility's default, which is usually different from the default chosen
         * by the AopProxy implementation's {@link #getProxy()} method.
         * @param classLoader the class loader to create the proxy with
         * (or {@code null} for the low-level proxy facility's default)
         * @return the new proxy object (never {@code null})
         */
        Object getProxy(ClassLoader classLoader);
    
    }
    View Code

      该接口有如下实现类:JdkDynamicAopProxy , CglibAopProxy , ObjenesisCglibAopProxy。

      那么在这里我们看一下JdkDynamicAopProxy的源码,我只贴出其中一个关键部分:

    @Override
        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);
        }

      那么我们可以看出:JDK的动态代理是AOP的实现方式之一

        

    三、基于AOP的核心类与接口实现代理

    1、先定义基本的JavaBean:

    package org.hzgj.spring.study;
    
    @Aop
    public class Water {
    
        private int capacity;
    
        public int getCapacity() {
            return capacity;
        }
    
        public void setCapacity(int capacity) {
            this.capacity = capacity;
        }
    
        public void test() {
            System.out.println("test");
        }
    
        @Aop
        public void test1() {
            System.out.println("test1");
        }
    }
    View Code

    2、自定义注解

    package org.hzgj.spring.study;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD,ElementType.TYPE})
    public @interface Aop {
    }
    View Code

    3、定义JavaBean的代理

    package org.hzgj.spring.study;
    
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    import org.springframework.aop.framework.AbstractSingletonProxyFactoryBean;
    import org.springframework.aop.support.DefaultPointcutAdvisor;
    import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
    import org.springframework.stereotype.Component;
    
    
    /**
     * 
     */
    @Component
    public class WaterProxyFactoryBean extends AbstractSingletonProxyFactoryBean {
    
    
        public WaterProxyFactoryBean() {
            super.setTarget(new Water());
        }
    
        @Override
        protected Object createMainInterceptor() {
            AnnotationMatchingPointcut pointcut = new AnnotationMatchingPointcut(Aop.class, Aop.class);
            DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, (MethodInterceptor) invocation -> {
                System.out.println(1);
                return invocation.proceed();
            });
    
            return advisor;
        }
    }
    View Code

      该类继承AbstractSingletonProxyFactoryBean,然后需要重写createMainInterceptor,我在这里定义了一个DefaultPointcutAdvisor与扫描注解的PointCut,至此切点,通知,代理都有了,那么AOP最基本的条件也就具备了

    4、主程序

    package org.hzgj.spring.study;
    
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Main {
    
        public static void main(String[] args) {
        
    
            ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");
            Water water = applicationContext.getBean(Water.class);
            water.test1();
        }
    }
    View Code

      运行成功时会得到如下结果:

  • 相关阅读:
    xml根据属性去重。如csprj去重
    table中td的内容换行。
    基于jq的表单填充
    c#包含类文件到csprj中
    t4 根据表名数组生成实体
    js中找string中重复项最多的字符个数
    一步步配置cordova android开发环境
    .net framework卸载工具
    Sql Server查询视图和表
    DbHelper.ttinclude 更新,查询视图和表
  • 原文地址:https://www.cnblogs.com/niechen/p/9016816.html
Copyright © 2011-2022 走看看