使用Spring配置AOP拦截的常用方式

7 篇文章 0 订阅

废话少说,直接上Spring的配置文件


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd 
	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd 
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"
	default-lazy-init="true">
	
	<bean id="services" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target">
			<ref bean="servicesTarget"/>
		</property>
		<property name="interfaces">
			<list>
				<value>test.test.aop.IServices</value>
			</list>
		</property>
		<property name="proxyTargetClass">
			<value>false</value>
		</property>
		<property name="interceptorNames">
			<list>
				<value>defaultPointcutAdvisor</value>
			<!-- 
				<value>nameMatchMethodPointcutAdvisor</value>
				<value>regexpMethodPointcutAdvisor</value>
				<value>myAdvice</value>
				<value>defaultPointcutAdvisor</value>
			 -->
			</list>
		</property>
	</bean>
	
	<bean id="servicesTarget" class="test.test.aop.ServicesImpl" />
	
	<bean id="myAdvice" class="test.test.aop.MyAdvice" />
	
	<!-- 根据方法名称匹配来创建切入点 -->
	<bean id="nameMatchMethodPointcutAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
		<property name="mappedName">
			<value>foo2</value>
		</property>
		<property name="advice">
			<ref bean="myAdvice" />
		</property>
	</bean>
	
	<!-- 根据正则表达式匹配方法名称来创建切入点 -->
	<bean id="regexpMethodPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
		<property name="pattern">
			<value>.*2$</value>
		</property>
		<property name="advice">
			<ref bean="myAdvice"/>
		</property>
	</bean>
	
	<!-- 根据Pointcut和Advice 创建PointcutAdvisor-->
	<bean id="defaultPointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
		<property name="pointcut">
			<ref bean="controlFlowPointcut"/>
		</property>
		<property name="advice">
			<ref bean="myAdvice" />
		</property>
	</bean>
	<!-- 动态切入点 根据运行时堆栈和方法信息判断切入点 -->
	<bean id="controlFlowPointcut" class="org.springframework.aop.support.ControlFlowPointcut">
		<constructor-arg>
			<!-- 注意这里不能配置service接口或实现类的class名称,因为servcie类或接口已经被代理了 -->
			<value>test.test.aop.TestMain</value>
		</constructor-arg>
		<constructor-arg>
			<value>main</value>
		</constructor-arg>
	</bean>
	 
	<!-- 根据bean names动态代理 -->
	<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="proxyTargetClass" value="false" />
        <property name="beanNames">
            <list>
                <value>servicesTarget2</value>
            </list>
        </property>
        <property name="interceptorNames">
            <list>
				<value>regexpMethodPointcutAdvisor</value>
				<!-- 
				<value>nameMatchMethodPointcutAdvisor</value>
				<value>regexpMethodPointcutAdvisor</value>
				<value>myAdvice</value>
				<value>defaultPointcutAdvisor</value>
				 -->
			</list>
        </property>
    </bean>
    <!-- 重现定义一个bean name,避免被 BeanNameAutoProxyCreator 重复代理-->
    <bean id="servicesTarget2" class="test.test.aop.ServicesImpl" />
    
</beans>

这份配置文件较为冗长,咋一看比较复杂,但如果仔细分析,我们会发现其实没有那么复杂。

我们先从最基础的元素开始,test.test.aop.IServices是我们定义的一个业务接口,里面有两个业务方法,foo()和foo2();

test.test.aop.ServicesImpl是test.test.aop.IServices的具体实现。

再来看与AOP相关的配置,这里我们需要简单的解释几个概念,一个是Advice,这个在有写文档里面称为“增强”或者“通知”,其实可以更直观的理解为一个方法被拦截后做其他相关事情的地方。它的一般实现是实现一个org.aopalliance.intercept.MethodInterceptor接口,并实现其invoke方法,在该方法实现中,通过MethodInvocation.proceed()可以调用到目标方法。

另外一个相关的概念就是Pointcut,就是切面,更直观一点的理解就是在什么时候会被拦截。而Spring定义了另外一个概念,即PointcutAdvisor,即将Pointcut对象和Advice对象组合在一起,决定在什么地方,做什么的动作。

有了业务接口、业务实现(目标)、横切面和通知,那么是什么让这些元素组合在一起呢?在Spring中就是通过代理的方式,将上述的这些元素组合在一起,org.springframework.aop.framework.ProxyFactoryBean就是最常用的一个代理工厂Bean,其可以产生相应的代理对象。它由如下几个重要的属性将业务接口、业务实现、横切面和通知(PointcutAdivsor)整合在一起。

interfaces属性,指定需要代理的接口;

target属性,指定代理对象的目标对象(可以参考设计模式的代理模式);

proxyTargetClass属性,true或者false,true表示通过类代理,false表示通过接口代理,跟具体的区别在与,如果为true,那么需要使用GCLib来生成目标对象的子类,这样要要求目标对象类不能为final,并且需要拦截的方法,也不能为final的。因为final的类和方法没有办法生成子类和重写父类的方法。

interceptorNames属性就是将设置PointcutAdvisor的地方,这里可以将Advisor,也就是之前定义的通知,直接配置到这里,那么目标对象的所有方法都将被拦截。

我们再来详细解释一下PointcutAdivsor这个对象。刚才已经提到PointcutAdivsor对象实际上是Pointcut对象和Adivsor对象的组合,Adivsor对我们已经有了,也就是org.aopalliance.intercept.MethodInterceptor接口对象的实现。那么Pointcut这个对象该如何定义呢?其实Spring已经帮我们定义好了几个默认的实现,我们只需要简单的配置即可。先来看最常用的org.springframework.aop.support.NameMatchMethodPointcutAdvisor对象,该对象内部已经包含了一个org.springframework.aop.support.NameMatchMethodPointcut对象,顾名思义,通过匹配方法名称来定义Pointcut对象,所以我们在配置org.springframework.aop.support.NameMatchMethodPointcutAdvisor对象的时候,配置一个方法匹配的名称,实际上在其内部是生成了一个org.springframework.aop.support.NameMatchMethodPointcut对象。

另外一个也比较常用的PointcutAdvisor是org.springframework.aop.support.RegexpMethodPointcutAdvisor,即通过正则表达式来匹配方法的名称,同样,其内部也是包含了一个org.springframework.aop.support.AbstractRegexpMethodPointcut抽象对象,具体实现为org.springframework.aop.support.JdkRegexpMethodPointcut。

org.springframework.aop.support.DefaultPointcutAdvisor是一个更一般性的PointcutAdvisor对象,可以运行自己定义自己的Pointcut和Advisce。


上述配置Ok之后,一切就大功告成了。但这里有一个小问题就是每一个业务接口和其业务实现,我们都需要配置一个ProxyFactoryBean。那么有什么办法能简化这个过程呢?答案就是使用org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator对象,该对象能够根据我们配置的bean name来确定那些bean对象需要被代理,并创建出其代理对象。同样在代理时需要确定是通过接口代理还是类代理,即proxyTargetClass属性。同样需要配置interceptorNames属性,即PointcutAdvisor列表。

威力更大的是org.springframework.aop.support.DefaultAdvisorAutoProxyCreator对象,该对象会自动扫描Spring配置文件中,将符合定义在其interceptorNames属性的PointcutAdvisor对象的所有bean自动产生代理对象。


这里可以下载上述配置实例的代码,但需要引用Sping2.0以上的包才能运行。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值