• Spring aop的多种配置方式以及源码分析


        profile是Spring3.1提供的一个新的配置项,在下面的测试示例中,又有使用了多种AOP配置方式,为了将各种配置方式进行对比在此使用了profile.在测试用例中通过使用@ActiveProfiles("four")注解指定profile的值。

      Aop 是Spring 框架的核心功能之一。

        Advice 通知时定义在该连接点做什么,为切面增强提供织入接口。Advice是AOP联盟定义的一个接口,在Spring中对其进行了扩展,提供了更为具体的接口如:BeforeAdvice,AfterAdvice,ThrwosAdvice等。

     Pointcut切点,决定advice通知应该作用于哪个连接点,也就是说Pointcut来定义需要增强方法的集合,这些集合的选取可以按照一定的规则来完成。Spring中默认提供了JdkRegexpMethodPointcut,基于正则表达式去匹配增强方法。

       Advisor通知器,在完成对既定目标的增强切面的设计(advice)和关注点的设计(Pointcut)以后,还需要将Advice和Pointcut两者关联起来,完成这个工作的就是Advisor. 通过Advisor,可以定义在哪个关注点上使用哪个通知。在Spring 中默认提供了一个DefultPointcutAdvisor,并以此为例完成AOP demo.

        在Spring AOP 使用中可以通过ProxyFactoryBean来配置目标对象和切面的行为。在ProxyFactoryBean中通过interceptorNames属性来配置已经定义好的advisor.虽然名字是interceptor实际上就是配置advisor.在ProxyFactoryBean中需要为target目标对象生成一个动态代理对象proxy,从而为AOP切面的编织做好准备工作。

           ProxyFactoryBean对象中创建一个代理对象的过程是:

    1. addGlobalAdvisor
    2. getSingletonInstance
    /**
    	 * 返回一个代理对象。当客户端从这个FactoryBean中获取bean时调用该接口
    	 */
    	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.");
    			}
    			//返回以prototype实例
    			return newPrototypeInstance();
    		}
    	}
    	/**
    	 * 返回一个单例的代理对象
    	 */
    	private synchronized Object getSingletonInstance() {
    		if (this.singletonInstance == null) {
    			this.targetSource = freshTargetSource();
    			if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
    				// 根据AOP框架来判断需要代理的接口
    				Class targetClass = getTargetClass();
    				if (targetClass == null) {
    					throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
    				}
    				//设置代理接口
    				setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
    			}
    			// 初始化一个单例
    			super.setFrozen(this.freezeProxy);
    			this.singletonInstance = getProxy(createAopProxy());
    		}
    		return this.singletonInstance;
    	}
    
    	
    
    	/**
    	 * 创建一个通知器链
    	 */
    	private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
    		//如果通知器链已经初始化则直接返回
    		if (this.advisorChainInitialized) {
    			return;
    		}
    	   // 如果没有配置过通知器则抛出异常
    		if (!ObjectUtils.isEmpty(this.interceptorNames)) {
    			if (this.beanFactory == null) {
    				throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
    						"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
    			}
    
    			//如果没有指定targetSource则最后一个通知器不能是全局通知器
    			if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
    					this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
    				throw new AopConfigException("Target required after globals");
    			}
    
    			// 通过通知器名称获取通知器对象
    			for (String name : this.interceptorNames) {
    				if (logger.isTraceEnabled()) {
    					logger.trace("Configuring advisor or advice '" + name + "'");
    				}
    				//如果通知器名称是以*结尾的且beanFactory不适ListableBeanFactory则抛出异常,否则添加全局通知器
    				if (name.endsWith(GLOBAL_SUFFIX)) {
    					if (!(this.beanFactory instanceof ListableBeanFactory)) {
    						throw new AopConfigException(
    								"Can only use global advisors or interceptors with a ListableBeanFactory");
    					}
    					addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
    							name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
    				}
    
    				else {
    					//非全局通知器
    					Object advice;
    					//如果该beanFactory是单例的或者是通知器是单例的则从beanFactory中获取单例的通知器,否则获取一个原型的通知器
    					if (this.singleton || this.beanFactory.isSingleton(name)) {
    						advice = this.beanFactory.getBean(name);
    					}
    					else {
    						
    						advice = new PrototypePlaceholderAdvisor(name);
    					}
    					//添加到通知器链中
    					addAdvisorOnChainCreation(advice, name);
    				}
    			}
    		}
    		//设置通知器初始化完成标识
    		this.advisorChainInitialized = true;
    	}
    
    
    
    	/**
    	 * 添加所有的通知器和切点
    	 */
    	private void addGlobalAdvisor(ListableBeanFactory beanFactory, String prefix) {
    	  //获取beanFactory中定义的所有的通知器
    		String[] globalAdvisorNames =
    				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Advisor.class);
    	  // 获取beanFactory中定义的所有的Interceptor
    		String[] globalInterceptorNames =
    				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Interceptor.class);
    	
    		List<Object> beans = new ArrayList<Object>(globalAdvisorNames.length + globalInterceptorNames.length);
    		Map<Object, String> names = new HashMap<Object, String>(beans.size());
    		//遍历所有的通知器
    		for (String name : globalAdvisorNames) {
    			Object bean = beanFactory.getBean(name);
    			beans.add(bean);
    			names.put(bean, name);
    		}
    		//遍历所有拦截器
    		for (String name : globalInterceptorNames) {
    			Object bean = beanFactory.getBean(name);
    			beans.add(bean);
    			names.put(bean, name);
    		}
    		//排序
    		OrderComparator.sort(beans);
    		//遍历所有,如果拦截器或通知器是以指定的前缀开始的则添加到通知器中
    		for (Object bean : beans) {
    			String name = names.get(bean);
    			if (name.startsWith(prefix)) {
    				addAdvisorOnChainCreation(bean, name);
    			}
    		}
    	}
    
    	/**
    	 * 添加一个通知器
    	 */
    	private void addAdvisorOnChainCreation(Object next, String name) {
    	    //转换为一个通知器
    		Advisor advisor = namedBeanToAdvisor(next);
    		if (logger.isTraceEnabled()) {
    			logger.trace("Adding advisor with name '" + name + "'");
    		}
            //添加通知器		
    		addAdvisor(advisor);
    	}
    
    }
    

       在ProxyFactoryBean中 getSingletoneInstance中有调用一个createAopProxy(),该方法是定义在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);
    			}
    			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);
    		}
    	}
    

          通过上述代码可以发现Spring AOP中,是通过CGLIB或者JDK 动态代理实现的。

    	public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
    		Assert.notNull(config, "AdvisedSupport must not be null");
    		if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
    			throw new AopConfigException("No advisors and no TargetSource specified");
    		}
    		this.advised = config;
    	}
       到此我们已经完成了一个代理对象创建。当我们创建一个代理对象后调用代理对象时则会触发InvocationHandler接口的invoke方法
    /**
    	 * InvocationHandler接口的invoke实现方法
    	 */
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		MethodInvocation invocation;
    		Object oldProxy = null;
    		boolean setProxyContext = false;
    		//获取TargetSource
    		TargetSource targetSource = this.advised.targetSource;
    		Class targetClass = null;
    		Object target = null;
    
    		try {
    		  //如果目标对象没有实现equals方法
    			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
    				// The target does not implement the equals(Object) method itself.
    				return equals(args[0]);
    			}
    			//如果目标对象没有实现hashCode
    			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)) {
    				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
    			}
    
    			Object retVal;
    
    			if (this.advised.exposeProxy) {
    				// Make invocation available if necessary.
    				oldProxy = AopContext.setCurrentProxy(proxy);
    				setProxyContext = true;
    			}
    
    			
    			// 获取目标对象
    			target = targetSource.getTarget();
    			//如果目标对象不是null,则初始化targetClass
    			if (target != null) {
    				targetClass = target.getClass();
    			}
    
    			// 获取这个方法的拦截器链
    			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
    			//如果拦截器链为空则表示这个方法配置配拦截器,则直接调用target对应的方法
    			if (chain.isEmpty()) {
    	
    				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
    			}
    			else {
    				//如果有配置拦截器,那么需要构建一个ReflectiveMethodInvocation
    				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
    				// 沿着拦截器链进行处理
    				retVal = invocation.proceed();
    			}
    
    			if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) &&
    					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
    				retVal = proxy;
    			}
    			return retVal;
    		}
    		finally {
    			if (target != null && !targetSource.isStatic()) {
    				targetSource.releaseTarget(target);
    			}
    			if (setProxyContext) {
    				AopContext.setCurrentProxy(oldProxy);
    			}
    		}
    	}
    
     

       在上述的代码中有一个getInterceptorsAndDynamicInterceptionAdvice()获取拦截器链

    	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {
    		MethodCacheKey cacheKey = new MethodCacheKey(method);
    		List<Object> cached = this.methodCache.get(cacheKey);
    		if (cached == null) {
    			cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
    					this, method, targetClass);
    			this.methodCache.put(cacheKey, cached);
    		}
    		return cached;
    	}
     
    	protected ReflectiveMethodInvocation(
    			Object proxy, Object target, Method method, Object[] arguments,
    			Class targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
    
    		this.proxy = proxy;
    		this.target = target;
    		this.targetClass = targetClass;
    		this.method = BridgeMethodResolver.findBridgedMethod(method);
    		this.arguments = arguments;
    		this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
    	}
    
     
    public Object proceed() throws Throwable {
    		//	We start with an index of -1 and increment early.
    		//   从-1的索引位置开始先自增后执行拦截器,如果当前索引已经是最后一个则直接调用这个连接点
    		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
    			return invokeJoinpoint();
    		}
    		//获取指定索引位置的拦截器
    		Object interceptorOrInterceptionAdvice =
    		    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    		// 如果拦截器是InterceptorAndDynamicMethodMatcher
    		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
    			
    			InterceptorAndDynamicMethodMatcher dm =
    			    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
    				//如果拦截器匹配方法成功则实行该拦截器
    			if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
    				return dm.interceptor.invoke(this);
    			}
    			else {
    				// 如果匹配失败则跳过该拦截器,执行下一个拦截器
    				return proceed();
    			}
    		}
    		else {
    			// 如果是一个拦截器则直接调用
    			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    		}
    	}

     到此我们已经可以对Spring AOP 有一个基本的认识!下面是一个DEMO的实现

    /**
     *  方法调用前的权限拦截器
     * @author zhangwei_david
     * @version $Id: AuthInterceptor.java, v 0.1 2015年7月10日 上午10:18:12 zhangwei_david Exp $
     */
    public class AuthInterceptor implements MethodBeforeAdvice {
    
        /**
         * @see org.springframework.aop.MethodBeforeAdvice#before(java.lang.reflect.Method, java.lang.Object[], java.lang.Object)
         */
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println("调用 方法:" + method);
        }
    
    }
    /**
     *
     * @author zhangwei_david
     * @version $Id: AopDemo.java, v 0.1 2015年7月10日 上午10:21:20 zhangwei_david Exp $
     */
    public class AopDemo implements Say {
    
        public void say() {
            System.out.println("hello");
        }
    }
    
    /**
     *
     *
     * @author zhangwei_david
     * @version $Id: SpringAopTest.java, v 0.1 2015年7月10日 上午10:51:16 zhangwei_david Exp $
     */
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath*:META-INF/spring/aop-beans.xml")
    public class SpringAopTest {
    
        @Autowired
        private Say aopDemo;
    
        @Test
        public void test() {
            aopDemo.say();
        }
    
    }
    
    2015-07-10 10:40:14  [ main:375 ] - [ INFO ]  Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@190a65e: defining beans [authInterceptor,authPoint,authAdvisor,aopDemo,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
    调用 方法:public abstract void com.cathy.demo.spring.aop.Say.say()
    hello
    2015-07-10 10:40:14  [ Thread-0:494 ] - [ INFO ]  Closing org.springframework.context.support.GenericApplicationContext@ee68d8: startup date [Fri Jul 10 10:40:14 CST 2015]; root of context hierarchy
    2015-07-10 10:40:14  [ Thread-0:494 ] - [ INFO ]  Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@190a65e: defining beans [authInterceptor,authPoint,authAdvisor,aopDemo,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
    

    其他的配置方式如下:

    /**
     *  方法调用前的权限拦截器
     * @author zhangwei_david
     * @version $Id: AuthInterceptor.java, v 0.1 2015年7月10日 上午10:18:12 zhangwei_david Exp $
     */
    @Component
    @Aspect
    public class BeforeInterceptor {
    
        @Before("execution(* *.*(..))")
        public void before(JoinPoint joinPoint) throws Throwable {
            System.out.println("before [target" + joinPoint.getTarget() + ", signature:"
                    + joinPoint.getSignature());
        }
    
    }
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jee="http://www.springframework.org/schema/jee"
    	xmlns:task="http://www.springframework.org/schema/task" xmlns:util="http://www.springframework.org/schema/util"
    	xmlns:jaxws="http://cxf.apache.org/jaxws"
    	xsi:schemaLocation="
    		http://www.springframework.org/schema/beans
    		http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    		http://www.springframework.org/schema/context
    		http://www.springframework.org/schema/context/spring-context-3.0.xsd
    		http://www.springframework.org/schema/aop 
    		http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    		http://www.springframework.org/schema/tx
    		http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    		http://www.springframework.org/schema/jee 
    		http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
    		http://www.springframework.org/schema/task  
            http://www.springframework.org/schema/task/spring-task-3.1.xsd  
            http://www.springframework.org/schema/util
            http://www.springframework.org/schema/util/spring-util-3.0.xsd
            http://cxf.apache.org/jaxws
            http://cxf.apache.org/schemas/jaxws.xsd
    		"
    	default-autowire="byType">
    	<!-- 使用ProxyFactoryBean 实现aop -->
    	<beans profile="one">
    		<!-- 定义一个通知 -->
    		<bean id="authInterceptor" class="com.cathy.demo.spring.aop.AuthInterceptor" />
    		<!-- 定义切点,匹配所有方法 -->
    		<bean id="authPoint"
    			class="org.springframework.aop.support.JdkRegexpMethodPointcut">
    			<property name="pattern" value=".*" />
    		</bean>
    
    		<!-- 定义通知 器 -->
    		<bean id="authAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
    			<property name="pointcut" ref="authPoint" />
    			<property name="advice" ref="authInterceptor" />
    		</bean>
    
    
    		<bean id="aopDemo" class="org.springframework.aop.framework.ProxyFactoryBean">
    			<property name="target">
    				<bean class="com.cathy.demo.spring.aop.AopDemo" />
    			</property>
    			<property name="interceptorNames" value="auth*" />
    
    		</bean>
    
    	</beans>
    	<!-- 优化配置,使用DefaultAdvisorAutoProxyCreator -->
    	<beans profile="two">
    		<!-- 定义一个通知 -->
    		<bean id="authInterceptor" class="com.cathy.demo.spring.aop.AuthInterceptor" />
    
    		<!-- 定义通知 器 -->
    		<bean id="authAdvisor"
    			class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    			<property name="pattern" value=".*" />
    			<property name="advice" ref="authInterceptor" />
    		</bean>
    
    
    		<bean
    			class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
    			p:usePrefix="true" p:advisorBeanNamePrefix="auth" />
    		<bean id="aopDemo" class="com.cathy.demo.spring.aop.AopDemo" />
    	</beans>
    	<!-- 使用aop命名空间进行配置 -->
    	<beans profile="three">
    		<bean id="authInterceptor" class="com.cathy.demo.spring.aop.BeforeInterceptor" />
    		<bean id="aopDemo" class="com.cathy.demo.spring.aop.AopDemo" />
    		<aop:config>
    			<aop:aspect ref="authInterceptor">
    				<aop:before method="before" pointcut="execution(* *.*(..))" />
    			</aop:aspect>
    		</aop:config>
    	</beans>
    	<!-- 自动扫描 @Aspectj -->
    	<beans profile="four">
    		<aop:aspectj-autoproxy />
    
    		<context:annotation-config />
    		<context:component-scan base-package="com.cathy.demo.spring.*" />
    	</beans>
    
    
    
    </beans>
    /**
     *
     *
     * @author zhangwei_david
     * @version $Id: SpringAopTest.java, v 0.1 2015年7月10日 上午10:51:16 zhangwei_david Exp $
     */
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath*:META-INF/spring/aop-beans.xml")
    @ActiveProfiles("four")
    public class SpringAopFourTest {
    
        @Autowired
        private Say aopDemo;
    
        @Test
        public void test() {
            aopDemo.say();
        }
    
    }
    

     更多关于AOP切点表达式

  • 相关阅读:
    颠覆想象的php解析获取跨域HTML标签
    Win7承载网络配置——让你的手机无线上网吧
    Joomla!备忘手记
    jQuery+PHP+MySQL简单无限级联实现
    js 功能函数集
    PHP POST数据至远程服务器获取信息
    js生成迅雷地址
    强大的jQuery选择器之选定连续多行
    札记 PHP/JS/jQuery/MySQL/CSS/正则/Apache
    php数组一对一替换
  • 原文地址:https://www.cnblogs.com/wei-zw/p/8797752.html
Copyright © 2020-2023  润新知