在Spring 2.0之前,Spring通过定义一套接口和通过ProxyFactoryBean来生产bean实例提供对AOP的支持,在2.0后,Spring推荐通过AspectJ兼容的方式来实现AOP.见http://blog.csdn.net/kkdelta/archive/2010/04/22/5515882.aspx
1,定义'方面'拦截器,最常用的接口有:
MethodInterceptor: 在方法执行的前后执行,相当于2.0的@Around.
MethodBeforeAdvice:在方法执行前执行,相当于2.0的@Before.
ThrowsAdvice :在方法异常后执行,相当于2.0的@AfterThrowing.
AfterReturningAdvice :在方法执行后执行,相当于2.0的@AfterReturning.
2,配置ProxyFactoryBean,使用ProxyFactoryBean创建AOP代理.最常用的配置项:
proxyInterfaces : 需要代理的接口名的字符串数组。如果没有提供,将为目标类使用一个CGLIB代理.
interceptorNames:Advisor的字符串数组,可以包括拦截器或其它advice的名字。顺序是很重要的,排在前面的将被优先服务。就是说列表里的第一个拦截器将能够第一个拦截调用。(Advisor是一个advice,在某些特定规则的方法执行的时候被触发)
target : 指定你希望代理的目标对象.
例子:
1,POJO bean类:
public interface IHelloWorld {
public String getContent(String helloworld);
public String testExp(String exp);
}
public interface IHelloWorld2 {
public String testExp2(String exp);
}
public class HelloWorld implements IHelloWorld,IHelloWorld2 {
protected static final Log log = LogFactory.getLog(HelloWorld.class);
public String getContent(String helloworld) {
log.info(helloworld);
return helloworld;
}
public String testExp(String exp){
log.info(exp);
return exp;
}
public String testExp2(String exp){
log.info("testExp2 " + exp);
return exp;
}
}
advice 类:
public class LoggingBeforeAdvice implements MethodBeforeAdvice {
protected static final Log log = LogFactory.getLog(LoggingBeforeAdvice.class);
public void before(Method m, Object[] args, Object target) throws Throwable {
log.info("before: The Invocation The Invocation of " + m.getName());
}
}
public class LoggingAfterAdvice implements AfterReturningAdvice {
protected static final Log log = LogFactory.getLog(LoggingAfterAdvice.class);
public void afterReturning(Object object, Method m, Object[] args,
Object target) throws Throwable {
log.info("after: The Invocation of " + m.getName());
}
}
public class DebugInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Before: invocation=[" + invocation + "]");
Object rval = invocation.proceed();
System.out.println("Invocation returned");
return rval;
}
}
配置文件:
<beans>
<bean id="helloworldbean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<list>
<value>com.test.spring.aop.api.IHelloWorld</value>
<value>com.test.spring.aop.api.IHelloWorld2</value>
</list>
</property>
<property name="target">
<ref local="helloworldbeanTarget" />
</property>
<property name="interceptorNames">
<list>
<value>loggingBeforeAdvice</value>
<value>debugInterceptor</value>
</list>
</property>
</bean>
<bean id="helloworldbeanTarget" class="com.test.spring.aop.api.HelloWorld" />
<bean id="loggingAfterAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref local="loggingAfterAdvice" />
</property>
<property name="pattern">
<value>.*</value>
</property>
</bean>
<bean id="loggingBeforeAdvice" class="com.test.spring.aop.api.LoggingBeforeAdvice" />
<bean id="loggingAfterAdvice" class="com.test.spring.aop.api.LoggingAfterAdvice" />
<bean id="debugInterceptor" class="com.test.spring.aop.api.DebugInterceptor" />
</beans>
调用代码:
ApplicationContext context = new ClassPathXmlApplicationContext("conf/aopapiAppcontext1.xml");
IHelloWorld bean = (IHelloWorld) context.getBean("helloworldbean");
try {
bean.getContent("helloworld");
bean.testExp("test RegexpMethodPointcutAdvisor");
IHelloWorld2 bean2 = (IHelloWorld2)bean;
bean2.testExp2("2 test RegexpMethodPointcutAdvisor");
} catch (Exception e) {
}
一种较好的方法是对某一类bean设置相同的切面设置,如下:
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames"><value>hello*</value></property>
<property name="proxyTargetClass" value="true"/>
<property name="interceptorNames">
<list>
<value>debugInterceptor</value>
</list>
</property>
</bean>
<bean id="helloworldbeanTarget" class="com.test.spring.aop.api.HelloWorld" />
<bean id="debugInterceptor" class="com.test.spring.aop.api.DebugInterceptor" />
还可以定义一个模板bean,其他bean"继承"这个bean的定义,如事务管理
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"/>
<bean id="txProxyTemplate" abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="myService1" parent="txProxyTemplate">
<property name="target">
<bean class="org.springframework.samples.MyServiceImpl1">
</bean>
</property>
</bean>
<bean id="myService2" parent="txProxyTemplate">
<property name="target">
<bean class="org.springframework.samples.MyServiceImpl2">
</bean>
</property>
</bean>
对于2.0以后配置事务管理则更为简单了
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"/>
<aop:config>
<aop:pointcut id="yyyProcessMethods" expression="execution(* com.xxx.yyy.*.*Processor.*(..))" />
<aop:pointcut id="yyyProcessMethods" expression="execution(* com.xxx.yyy.srv.*service.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="yyyProcessMethods" />
</aop:config>
<tx:advice id="txAdvice">
<tx:attributes><tx:method name="*" propagation="REQUIRED" /></tx:attributes>
</tx:advice>