Spring中整合了AOP的功能,虽然有不足,没有专门作AOP框架的那么完美,可是用一用感受仍是不错的正则表达式
一些概念:spring
AOP 面向切面编程编程
aspect 切面/切面类(我我的认为一个真正被解耦的程序,切面类中的功能能够切入到 任何一个目标类中 无所谓是service层或者说是dao层中的类)框架
joinPoint 链接点测试
在spring的aop中只有 类中的方法 能够作链接点,每个方法均可以是一个链接点.spa
pointCut 切入点 代理
一组链接点的集合code
advice 通知/拦截器xml
用来控制切面类未来究竟是织入到切入点的前面、后面或者是抛异常的时候。对象
adivsor 加强器
用来筛选类中的哪些方法是咱们的链接点(哪些方法须要被拦截).
target 目标对象
proxy 代理对象
wave 织入
-----------------------
advice(通知)的类型:
前置通知(Before advice):
在某些链接点(join point)以前执行的通知
返回后通知(After returning advice):
在某些链接点(join point)正常完成后执行的通知(方法正常结束,没有异常)
抛出异常后通知(After throwing advice):
在某些链接点(join point)抛出异常退出时执行的通知
后通知(After (finally) advice):
当某些链接点(join point)退出的时候执行的通知
环绕通知(Around Advice):
包围一个链接点(join point)的通知,例如事务的处理,就须要这样的通知,由于事务须要在方法前开启,在方法后提交,以及方法抛出异常时候回滚
注:在spring中,链接点(join point)指的就是方法
Spring中提供了AOP的实现方式 在XMl中配置只须要三步就能够实现
1.配置目标类
2.配置拦截器(配置切面类【可选】)
3.配置代理对象
配置xml文件:
1.首先是配置目标类
<!-- 配置dao层对象 --> <bean id="dao" class="com.briup.aop.dao.AccountDaoImpl"/> <!-- 配置一个测试帐户 --> <bean name="account" class="com.briup.aop.pojo.Account"> <property name="id" value="1"></property> <property name="name" value="tom"></property> <property name="balance" value="1000"></property> </bean> <!-- 配置目标对象 --> <bean name="target" class="com.briup.aop.service.AccountServiceImpl"> <property name="accountDao" ref="dao"></property> <property name="account" ref="account"></property> </bean>
2.配置拦截器
<!-- 配置切面类 --> <bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean> <!-- 配置advice --> <bean name="beforeAdvice" class="com.briup.aop.before.BeforeAdvice"> <!-- 注入切面类对象 --> <property name="logger" ref="logger"></property> </bean>
3.配置代理对象
<!-- 这里使用的是spring的一个代理对象工厂类产生的 --> <bean name="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 注入目标对象 --> <property name="target" ref="target"></property> <!-- 注入目标对象所实现的接口 能够有多个接口 --> <!-- 注入代理类须要实现的接口 代理类实现接口与目标类实现接口相同 --> <property name="proxyInterfaces"> <list> <value>com.briup.aop.service.IAccountService</value> </list> </property> <!-- 注入advice 能够有多个 --> <property name="interceptorNames"> <list> <value>beforeAdvice</value> </list> </property> </bean>
这样配置有三个问题:
1.这个目标类对应接口下的方法都被加入了功能
2.须要为每个目标类进行配置
3.目标类必须实现接口
首先咱们解决第一个问题
咱们的Spring中提供了advisor(加强器),加强器包装了一下advice(拦截器),能够筛选向接口中的那个方法添加功能
1.首先是配置目标类
<!-- 配置dao层对象 --> <bean id="dao" class="com.briup.aop.dao.AccountDaoImpl"/> <!-- 配置一个测试帐户 --> <bean name="account" class="com.briup.aop.pojo.Account"> <property name="id" value="1"></property> <property name="name" value="tom"></property> <property name="balance" value="1000"></property> </bean> <!-- 配置目标对象 --> <bean name="target" class="com.briup.aop.service.AccountServiceImpl"> <property name="accountDao" ref="dao"></property> <property name="account" ref="account"></property> </bean>
2.配置拦截器
<!-- 配置切面类 --> <bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean> <!-- 配置advice --> <bean name="beforeAdvice" class="com.briup.aop.before.BeforeAdvice"> <!-- 注入切面类对象 --> <property name="logger" ref="logger"></property> </bean>
3.添加加强器
<!-- 配置advisor 加强器--> <!-- 做用:筛选要拦截(要代理)的方法 --> <bean name="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <!-- 注入advice--> <property name="advice" ref="beforeAdvice"></property> <!-- 注入须要被拦截的目标对象中的方法(链接点) --> <property name="patterns"> <list> <value>.*bankAction</value> <!--单个字符出现0到屡次--> </list> </property> </bean> <!--RegexpMethodPointcutAdvisor默认的正则表达式选择方法--> <!--NameMatchMethodPointcutAdvisor按照方法名匹配-->
4.配置代理对象
<!-- 这里使用的是spring的一个代理对象工厂类产生的 --> <bean name="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 注入目标对象 --> <property name="target" ref="target"></property> <!-- 注入目标对象所实现的接口 能够有多个接口 --> <!-- 注入代理类须要实现的接口 代理类实现接口与目标类实现接口相同 --> <property name="proxyInterfaces"> <list> <value>com.briup.aop.service.IAccountService</value> </list> </property> <!-- 注入advice/advisor 能够有多个 --> <property name="interceptorNames"> <list> <value>advisor</value> </list> </property> </bean>
咱们处理了第一个问题,被处理的方法能够指定了
咱们开始解决第二个问题
自动的进行配置:自动代理:DefaultAdvisorAutoProxyCreator类的使用
xml配置文件:
1.配置拦截器
<!-- 配置切面类 --> <bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean> <!-- 配置advice --> <bean name="beforeAdvice" class="com.briup.aop.before.BeforeAdvice"> <!-- 注入切面类对象 --> <property name="logger" ref="logger"></property> </bean>
2.添加加强器
<!-- 配置advisor --> <!-- 做用:筛选要拦截的方法 --> <bean name="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <!-- 注入advice --> <property name="advice" ref="beforeAdvice"></property> <!-- 注入须要被拦截的目标对象中的方法 --> <property name="patterns"> <list> <value>.*bankAction</value> </list> </property> </bean>
配置目标对象,这里的对象中只要有加强器中的方法,就能够看成代理对象,Cgilb代理默认的将含有加强器中的方法的
全部对象都进行了处理,好比如下这个target对象,从容器中拿出后就是加入了功能的了,可是这些对象得要放在一个容器下面
在Spring中最须要注意的就是对象在不在容器中,对象不在容器中就没办法受到Spring框架的控制了
<bean name="target" class="com.briup.aop.service.AccountServiceImpl"> </bean>
3.实现自动代理
<!-- 配置代理对象 --> <!-- 这里使用自动代理的方式 autoproxy --> <!-- 注意:这不是一个工厂类,因此不能用过proxy来拿代理对象 --> <bean name="proxy" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"> </bean>
这样作就能够自动的对须要功能的方法进行代理处理了,也不用实现接口了
使用自动代理的时候须要注意的方面:
1.当前的配置里面"必定要有"一个advisor的配置
2.不须要向自动代理类中注入任何信息
3.无论目标对象是否实现了一个或多接口,自动代理的方式都可以为它产生代理对象(CGLib的方式).
4.从spring容器中拿代理对象的时候,须要经过目标对象的名字来拿。
5.spring如何肯定配置文件中哪一个bean是做为目标对象:
经过advisor中筛选的方法,若是这个bean中含有advisor中所配置的方法,则这个bean未来称为咱们的目标对象进行代理
可是又有问题来了:
咱们对全部含有同名方法的类对象进行了处理,若是想为指定类对象中的方法进行处理呢?
Spring一样进行了处理:
经过名字进行自动代理:BeanNameAutoProxyCreator类的使用
xml配置文件:
1.配置拦截器
<!-- 配置切面类 --> <bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean> <!-- 配置advice --> <bean name="beforeAdvice" class="com.briup.aop.before.BeforeAdvice"> <!-- 注入切面类对象 --> <property name="logger" ref="logger"></property> </bean>
2.添加加强器
<!-- 配置advisor --> <!-- 做用:筛选要拦截的方法 --> <bean name="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <!-- 注入advice --> <property name="advice" ref="beforeAdvice"></property> <!-- 注入须要被拦截的目标对象中的方法 --> <property name="patterns"> <list> <value>.*bankAction</value> </list> </property> </bean>
<!-- 配置目标对象 -->
<bean name="target" class="com.briup.aop.service.AccountServiceImpl"> </bean> <bean name="target2" class="com.briup.aop.service.AccountServiceImpl"> </bean> <bean name="target3" class="com.briup.aop.service.AccountServiceImpl"></bean>
3.实现自动代理
<!-- 配置代理对象 --> <!-- 这里使用自动代理的方式 autoproxybyname --> <bean name="proxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <!-- 注入须要被代理的对象名字 --> <property name="beanNames"> <list> <value>target</value> <value>target2</value> <value>dao</value> <value>service*</value> </list> </property> <!-- 注入advice或者advisor --> <property name="interceptorNames"> <list> <value>advisor</value> </list> </property> </bean>
使用byName自动代理的时候须要注意的方面:
1.当前的配置里面"有没有"advisor的配置"都不要紧"
有advisor能够精确选择增强功能的方法,没有就是类中的全部方法了
2.须要向自动代理类中注入被代理目标对象的名字已经advice或者advisor
就是说advisor中指定的方法在 被代理目标对象 中存在
3.无论目标对象是否实现了一个或多接口,自动代理的方式都可以为它产生代理对象.
4.从spring容器中拿代理对象的时候,须要经过目标对象的名字来拿。
这一点在DefaultAdvisorAutoProxyCreator的使用中就说过了
能够说 目标对象加入了功能,变成了代理对象
Spring中封装了AspectJ因此咱们也可使用到这种框架的功能了,Spring中提供了aop:config标签,使用aop的专用标签来完成相关的配置.这个标签我也是正在研究,听说挺好用的☺。