Spring的AOP
AOP(aspect oriented <['orɪɛntɪd]导向> Programming,面向切面编程)
AOP把一个业务流程分成几部分,例如权限检查、事务处理、日志记录,每个部分独立处理,然后把它们组装成完整的业务流程
aop小例子:
package com.aop; public interface IAopService { public void withAop() throws Exception; public void withoutAop() throws Exception; } package com.aop; import javax.security.auth.login.AccountException; public class AopServiceImpl implements IAopService { private String name; public void withAop() throws Exception { System.out.println("有AOP的函数运行。name:"+name); if(name.trim().length()==0){ throw new AccountException("name属性不能为空"); } } public void withoutAop() throws Exception { System.out.println("没有AOP的函数运行。"); } public String getName() { return name; } public void setName(String name) { this.name = name; } } package com.aop; import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; public class MethodAfterInterceptor implements AfterReturningAdvice{ public void afterReturning(Object value, Method method, Object[] arg2, Object instance) throws Throwable { System.out.println("方法"+method.getName()+"运行完毕,返回值为:"+value); } } package com.aop; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class MethodBeforeInterceptor implements MethodBeforeAdvice{ public void before(Method method, Object[] arg, Object instance) throws Throwable { System.out.println("即将要执行的方法:"+method.getName()); if(instance instanceof AopServiceImpl){ String name=((AopServiceImpl)instance).getName(); if(name==null){ throw new NullPointerException("name属性不能为null"); } } } } package com.aop; import java.lang.reflect.Method; import javax.security.auth.login.AccountException; import org.springframework.aop.ThrowsAdvice; public class ThrowsInterceptor implements ThrowsAdvice{ public void afterThrowing(Method method,Object[] args,Object instance,AccountException ex) throws Throwable{ System.out.println("方法"+method.getName()+"抛出了异常: "+ex); } public void afterThrowing(NullPointerException ex) throws Throwable{ System.out.println("抛出了异常: "+ex); } } package com.Test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.aop.IAopService; public class AopRun { @Test public static void main(String[]args) throws Exception{ ApplicationContext conte=new ClassPathXmlApplicationContext("applicationContext.xml"); IAopService hello=(IAopService)conte.getBean("aopService"); hello.withAop(); } } <?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="aopMethodBeforeInterceptor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <property name="advice"> <bean class="com.aop.MethodBeforeInterceptor"></bean> </property> <property name="mappedName" value="withAop"></property> </bean> <bean id="aopMethodAfterInterceptor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <property name="advice"> <bean class="com.aop.MethodAfterInterceptor"> </bean> </property> <property name="mappedName" value="withAop"></property> </bean> <bean id="aopThrowsInterceptor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <property name="advice"> <bean class="com.aop.ThrowsInterceptor"></bean> </property> <property name="mappedName" value="withAop"></property> </bean> <!-- Service对象,安装到ProxyFactoryBean对象中 --> <bean id="aopService" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="interceptorNames"> <list> <value>aopMethodBeforeInterceptor</value> <value>aopMethodAfterInterceptor</value> <value>aopThrowsInterceptor</value> </list> </property> <property name="target"> <bean class="com.aop.AopServiceImpl"> <property name="name" value="sss"></property> </bean> </property> </bean> </beans>
拦截器与Filter的区别
Spring的拦截器与Servlet的Filter有相似之处,比如二者都是AOP编程思想的体现,能实现权限检查、日志记录等等。不同的是:
1、使用范围不同:Filter是Servlet规范规定的,只能用于Web程序中。而拦截器既可以用于Web程序,也可以用于Application、Swing程序中
2、规范不同:Filter实在Servlet规范中定义的,是Servlet容器支持的。而拦截器是Spring容器内的,是Spring框架支持的。
3、使用的资源不同:同其他的代码块一样,拦截器也是一个Spring组件,归Spring管理,配置在Spring文件中,因此能使用Spring里的任何资源、对象,例如Service对象、数据源、事务管理等,通过IoC注入到拦截器即可,Filter不能
4、深度不同:Filter只在Servlet前后起作用。而拦截器能够深入到方法前后、异常抛出前后等等,因此拦截器具有更大的弹性。所以在Spring构架的程序中,要优先使用拦截器。
AOP的相关概念
1、切面 Aspect:在本例中,方法withAop()、withoutAop()中都有一些代码。虽然只是一些输出语句,但是在真实的程序中这里应该是一些有意义的代码(如读写数据库、权限检查、异常情况记录等等)。这些代码可以看做事AOP中的切面(Aspect)。可以将切面理解成模块
2、通知Advisor:本例的三个拦截器都是实现自某个Advise接口。从类名上看就知道三个拦截器就是AOP中的通知(Adcisor)。一旦Spring复合条件,就会派发出通知。与生活中的通知不同的是,Spring的通知是带有执行代码的,能实现某种功能。
3、切入点Pointcut:在配置拦截器的时候,XML只配置了withAop()方法使用拦截器,而withoutAop()方法没有配置拦截器。这种配置时借助于org.springframework.aop.support.NameMathMethodPointcutAdvisor完成的。从类名称上看,这是一个切入点(Pointcut)。该类对象能够配置哪些方法使用拦截器,从哪个地方切进去。配置的时候可以使用通配符。该类名上也带有Adcisor是因为它是用通知(Advisor)实现的
简单地说,切入点负责往什么地方插入代码,而通知负责插入什么代码
4、切入点配置方式:Spring提供灵活的切入点配置方式,例如使用正则表达式。
<bean id="aopMethodAfterInterceptor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <bean class="com.aop.MethodAfterInterceptor"> </bean> </property> <property name="patterns"> <list> <value>.*withAop</value> <value>.*like.*</value> </list> </property> </bean> package com.Test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.aop.IAopService; public class AopRun { @Test public static void main(String[]args) throws Exception{ ApplicationContext conte=new ClassPathXmlApplicationContext("applicationContext.xml"); IAopService hello=(IAopService)conte.getBean("aopService"); hello.withAop(); hello.youlike(); } public static void slikeme(){ System.out.println("这是slikeme方法"); } } 其他不是很需要讲解的地方加了slikeme方法
注意:正则有点怪。(好像前面必须是.*)
AOP的代理模式
代理模式是Spring中常用的设计模式。Spring提供了几个常用的代理类,例如普通的代理类、事务处理类等等。
1、ProxyFactoryBean代理工厂对象
org.springframework.aop.framework.ProxyFactory.这是spring内置的代理类,引入了一个中间层,能够创建不同类型的对象。利用它可以实现任何形式的AOP
2、TransactionProxyFactoryBean事务代理工厂对象
TransactionProxyFactoryBean,是ProxyFactoryBean的子类,常用在数据库编程上。Spring、利用TransactionProxyFactoryBean对事务进行管理,在指定方法前利用AOP连接数据库并开启事务,然后在指定的方法返回后利用AOP提交事务并断开数据库。
<bean id=:petStoreTarget" class="......" ><!--代码实例-->
<property name="accountDao">
<ref bean="accountDao" />
<property> <!--设置DAO引用-->
</bean>
<bean id="petStore" class="org.springframework.interceptor.TransactionProxyFactoryBean"><!--安装事务管理bean-->
<property name="transactionManager" ref="transactionManager" /><!--事务管理Bean-->
<property name="target" ref="petStoreTaeget" /><!--安装到该bean-->
<property name="transactionAttributes"><!--方法名配置-->
<props>
<prop key="insert">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readoOnly</prop>
</props>
</property>
</beans>
注意:使用spring的aop的时候将ProxyFactoryBean只能转化成为接口类型。而不是它的实现类。