`
2007yn
  • 浏览: 44195 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Spring 中AOP的使用

阅读更多

 一提到AOP的应用,人们就会本能地提起日志功能,它就像一门语言的“Hello World”一样被人们无数次提起。也许有人会疑问除了“不实用”的日志功能,AOP还能做些什么?可能在很多时候我们并不需要自己实现一个AOP功能,尤其是在拥有了很多优秀的AOP应用框架来解决通用的横切性问题的情况下(比如Spring的事务管理、比如Acegi的安全管理、比如WebWork的拦截功能)。但问题总是层出不穷的,总会有些问题可能需要我们自己AOP一下。

        在月言月,进入到该文的主题(写完上面的一段使我想起俞平伯,那老头很多文章的前几段总是些不知所以的文字,直到“ 在月言月”一出,方进入文章主题;在看完文章后回头一瞧,和主题相关的文字竟不到文章的半数!)。这个Sample要实现的AOP功能是最简单的日志功能,在调用每个Service方法之前输出被调用方法的简单信息。

        我们知道,Aspect=Pointcut+Advice(如果您不知道的话,需要看一看Spring文档了)。在Spring1.X中,不能以AspectJ的语法书写复杂的切入点表达式(这是因为Spring1.X中的切入点是Java类)。Spring1.X可以使用正则表达式切入点以声明的方式来简化编程。这里假定要求对Service层中所有Service方法在调用之前输出和方法相关的信息。切入点声明如下:


<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><bean id="businessServicePointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">

<property name="patterns">

<value>*</value>

</property>

</bean>

应该说明的是,在不使用通知器自动代理的情况下,声明的切入点的作用域实在小的可怜,它不过是方法级别的。我觉得这也是Spring1.X中很不友好的一点,通过ProxyFactoryBean代理的方式实现AOP,需要对每个应用了AOP特性的Bean都做代理,即便是在Bean继承的情况下也不友好。

        下面要创建一个超简单的Before通知:


<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->public class LogAdvice implements MethodBeforeAdvice{

public void before(Method arg0, Object[] arg1, Object arg2) throws
 Throwable {

//no content


}

}


        关于通知和切面的配置如下:

 

<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><bean id="logAdvice" class="hibernatesample.service.util.LogAdvice"></bean>

<bean id="logAspect" class="org.springframework.aop.support.DefaultPointcutAdvisor">

<property name="pointcut" ref="businessServicePointcut"></property>

<property name="advice" ref="logAdvice"></property>

</bean>


 

        spring1.X中,AdvisorAspect的同义词,这是spring1.X独有的。坦率的说,我觉得这个词真不应该出现,它会给AOP初学者造成很大的困惑,尤其是对AspectJ不了解的情况下。在spring1.X中,我们并不需要自己编写一个Advisor,只需要使用Spring提供的Advisor封装切入点和通知就行了。如果你不使用通知器自动代理并且要通知作用的类的所有方法,Advisor甚至是不需要的。好了,上面就是我们自定义的一个日志切面,我们还要加一个切面--经典的对于Service必不可少的事务切面。配置文件如下:


<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><bean id="transactionManager"

class
="org.springframework.orm.hibernate3.HibernateTransactionManager">

<property name="sessionFactory">

<ref bean="sessionFactory" />

</property>

</bean>

<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">

<property name="transactionManager"><ref bean="transactionManager"/></property>

<property name="transactionAttributes">

<props>

<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>

<prop key="*">PROPAGATION_REQUIRED</prop>

</props>

</property>

</bean>


       
        你也看到了,transactionInterceptor是个拦截器,它只是对方法级别上做拦截.将transactionInterceptor和logAspect以ProxyFactoryBean方式作用到
Service上,配置文件如下:


<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><bean id="accountServiceTarget" class="hibernatesample.service.impl.AccountServiceImpl">

<property name="accountDAO" ref="accountDAO"></property>

</bean>


<bean id="accountService" class="org.springframework.aop.framework.ProxyFactoryBean">

<property name="proxyInterfaces">

<value>hibernatesample.service.AccountService</value>

</property>

<property name="interceptorNames">

<list>

<value>logAspect</value>

<value>transactionInterceptor</value>

</list>

</property>

<property name="target"><ref bean="accountServiceTarget"/></property>

</bean>

 

 


        如果我再定义一个
Service,我还是需要在使用了ProxyFactoryBeanService Bean中拷贝如下的内容而不同的是,它们之间只是更换了target属性:

<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><property name="proxyInterfaces">

<value>hibernatesample.service.AccountService</value>

</property>

<property name="interceptorNames">

<list>

<value>logAspect</value>

<value>transactionInterceptor</value>

</list>

</property>


          

 


        一个好的解决配置重复的办法是使用
Spring配置中继承特性,但此继承可不是OO中的继承,它只是将父Bean中的未声明的属性推到子Bean声明(target了),而父Bean去声明那些配置子Bean相同的内容(就是上面的内容)。简化后的内容如下:


<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><bean id="baseServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean" abstract="true">

<property name="interceptorNames">

<list>

<value>logAspect</value>

<value>transactionInterceptor</value>

</list>

</property>

</bean>


<bean id="accountService" parent="baseServiceProxy">

<property name="proxyInterfaces"><value>hibernatesample.service.AccountService</value></property>

<property name="target">

<bean class="hibernatesample.service.impl.AccountServiceImpl">

<property name="accountDAO" ref="accountDAO"></property>

</bean>

</property>

</bean>


        对于事务声明,除了采用通用的ProxyFactoryBean来拦截transactionInterceptor外,也可以采用TransactionProxyFactoryBean,它应该是变相的ProxyFactoryBeantransactionInterceptor。另外,可以使用TransactionProxyFactoryBeanpostInterceptors或者preInterceptors属性来配置其他切面(通知)。


<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><bean id="baseServiceProxy"

class
="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"

abstract
="true">

<property name="transactionManager" ref="transactionManager" />

<property name="transactionAttributes">

<props>

<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>

<prop key="*">PROPAGATION_REQUIRED</prop>

</props>

</property>

<property name="postInterceptors">

<ref bean="logAspect"/>

</property>

</bean>



    在简化Spring1.X文件配置方面,更好的选择是使用自动代理。这里介绍一下两个很好用的自动代理方式。

    第一种自动代理是使用BeanNameAutoProxyCreator,只需要指定它的beanNamesinterceptorNames,便可将interceptorNames列表中的切面(拦截器、通知)作用到匹配beanNamesBean。注意的是,beanNames可不是类名,而是配置文件中Bean名。示例如下:


<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><bean id="serviceNameAutoProxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<value>*Service</value>
</property>
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
<value>logAspect</value>
</list>
</property>
</bean>


     第二种自动代理方式是使用DefaultAdvisorAutoProxyCreator这在思想上已经是切面级的,而不是通知(拦截器)级的;也就是说,只有切面是一等公民,通知和拦截器已经不能脱离切入点而独立工作了。还是上面的例子,使用DefaultAdvisorAutoProxyCreator的配置如下:


<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><bean id="businessServicePointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">

<property name="patterns">

<value>hibernatesample.service.*</value>

</property>

</bean>

<bean id="logAdvice" class="hibernatesample.service.util.LogAdvice"></bean>

<bean id="logAspect" class="org.springframework.aop.support.DefaultPointcutAdvisor">

<property name="pointcut" ref="businessServicePointcut"></property>

<property name="advice" ref="logAdvice"></property>

</bean>

<bean id="serviceClassFilter" class="hibernatesample.service.util.ServiceClassFilter"></bean>

<bean id="txAdvisor"

class
="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">

<property name="transactionInterceptor">

<ref bean="transactionInterceptor"/>

</property>

<property name="classFilter" ref="serviceClassFilter"></property>

</bean>

<bean id="accountService" class="hibernatesample.service.impl.AccountServiceImpl">

<property name="accountDAO" ref="accountDAO"></property>

</bean>

<bean id="advisorAutoProxy" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">

</bean>


 

 

 

        相比于前面的配置方式,使用DefaultAdvisorAutoProxyCreator在配置文件上有了不少变化。首先是businessServicePointcut,其patterns可是要类(或包)级别的了。变化最大的就是事务声明了。这里引入了TransactionAttributeSourceAdvisor ,由于transactionInterceptortransactionAttributes只是方法级别的,因此需要一个classFilter来在类(包)级别上做匹配(这样切入点就完整了),引入的 ServiceClassFilter的定义如下:


<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->public class ServiceClassFilter implements ClassFilter{

public boolean
 matches(Class c) {

String name 
=
 c.getSimpleName();

if(name.indexOf("Service"== -1)return false
;

String pg 
=
 c.getPackage().getName();

if(!pg.startsWith("hibernatesample.service"))return false
;

return true
;

}

}


        好了,关于Spring1.XAOP的介绍到此结束了。在我重新整理Spring1.XAOP时,我更加觉得,Spring的配置文件太灵活了,同样的功能会有很多种配置方式,完整的、简洁的不一而足。对于开发者来说,需要根据自己的习惯来确定如何有效地操纵Spring1.XAOP实现。


分享到:
评论

相关推荐

    spring-aop.jar各个版本

    spring-aop-1.1.1.jar spring-aop-1.2.6.jar spring-aop-1.2.9.jar spring-aop-2.0.2.jar spring-aop-2.0.6.jar spring-aop-2.0.7.jar spring-aop-2.0.8.jar spring-aop-2.0.jar spring-aop-2.5.1.jar spring-aop-...

    开发工具 spring-aop-4.3.6.RELEASE

    开发工具 spring-aop-4.3.6.RELEASE开发工具 spring-aop-4.3.6.RELEASE开发工具 spring-aop-4.3.6.RELEASE开发工具 spring-aop-4.3.6.RELEASE开发工具 spring-aop-4.3.6.RELEASE开发工具 spring-aop-4.3.6.RELEASE...

    spring-aop-5.2.0.RELEASE-API文档-中文版.zip

    赠送jar包:spring-aop-5.2.0.RELEASE.jar; 赠送原API文档:spring-aop-5.2.0.RELEASE-javadoc.jar; 赠送源代码:spring-aop-5.2.0....人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。

    spring-aop-jar

    在Spring AOP中,切面可以通过注解或XML配置来定义。 - 连接点(Join Point):连接点是程序执行过程中的一个特定点,例如方法的调用或字段的访问。 - 切入点(Pointcut):切入点是连接点的集合,定义了切面将在...

    Spring使用AOP的三个jar包

    这三个jar包在Spring AOP中的角色如下: 1. `aspectjrt.jar`:提供AspectJ的运行时支持,用于实现基于AspectJ的切面。 2. `aspectjweaver.jar`:作为Spring AOP的核心,负责运行时织入,动态修改字节码以实现切面...

    Spring 2.5 AOP 例子

    Spring 2.5 AOP(面向切面编程)是Java应用程序中的一个重要概念,它允许开发者在不修改原有代码的情况下插入新的行为或监控。这个例子旨在帮助我们理解和应用Spring框架的AOP特性。以下是对该主题的详细解释: 一...

    spring-aop-5.0.10.RELEASE-API文档-中文版.zip

    赠送jar包:spring-aop-5.0.10.RELEASE.jar; 赠送原API文档:spring-aop-5.0.10.RELEASE-javadoc.jar; 赠送源代码:spring-aop-5.0.10....人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。

    spring-boot aop

    在Spring框架中,AOP主要用于日志记录、事务管理、性能统计等场景。本示例是关于如何在Spring Boot项目中实现AOP功能的一个简单演示。 首先,我们需要了解AOP的基本概念。AOP的核心是切面(Aspect),它封装了跨越...

    spring之AOP(动态代理)

    在Spring Boot项目中,配置和使用AOP相对简单。首先,我们需要引入Spring AOP和AspectJ的依赖,这通常在pom.xml或build.gradle文件中完成。然后,我们可以定义一个切面(Aspect),它包含通知(Advice)——即在特定...

    spring-aop-5.0.8.RELEASE-API文档-中英对照版.zip

    赠送jar包:spring-aop-5.0.8.RELEASE.jar; 赠送原API文档:spring-aop-5.0.8.RELEASE-javadoc.jar;...人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。 双语对照,边学技术、边学英语。

    spring,spring-aop-5.3.22.jar+aop+IDEA本地包

    spring-aop-5.3.22.jar Spring AOP provides an Alliance-compliant aspect-oriented programming implementation allowing you to define method interceptors and pointcuts to cleanly decouple code that ...

    spring-aop-5.3.12-API文档-中英对照版.zip

    赠送jar包:spring-aop-5.3.12.jar; 赠送原API文档:spring-aop-5.3.12-javadoc.jar;...人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。 双语对照,边学技术、边学英语。

    spring-aop-5.3.10-API文档-中文版.zip

    赠送jar包:spring-aop-5.3.10.jar; 赠送原API文档:spring-aop-5.3.10-javadoc.jar; 赠送源代码:spring-aop-5.3.10-sources.jar;...人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。

    spring-aop-6.0.2.jar

    spring-aop-6.0.2.jar

    spring-aop-3.2.0.RELEASE.jar

    spring-aop-3.2.0.RELEASE.jar,一个Spring中AOP的jar包

    spring-aop-5.2.15.RELEASE-API文档-中文版.zip

    赠送jar包:spring-aop-5.2.15.RELEASE.jar; 赠送原API文档:spring-aop-5.2.15.RELEASE-javadoc.jar; 赠送源代码:spring-aop-5.2.15....人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。

    Spring_aop源码

    Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的...通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中

    死磕Spring之AOP篇 - Spring AOP两种代理对象的拦截处理(csdn)————程序.pdf

    在 Spring AOP 中,`ObjenesisCglibAopProxy` 类负责使用 CGLIB 创建代理对象,它会将一系列的 `MethodInterceptor` 注册为 `Callback`,这些 `MethodInterceptor` 执行了 AOP 的逻辑。 在 Spring AOP 的自动代理...

    Spring进行AOP操作需要的4个jar包

    Spring进行aop操作需要的4个jar包,包括aopalliance-1.0.jar、aspectjweaver-1.8.9.jar、spring-aop-4.3.0.RELEASE.jar、spring-aspects-4.3.0.RELEASE.jar。

    spring-aop.jar

    在Spring AOP中,切面通常包括通知(advice)和切点(pointcut)。通知定义了在特定的切点上执行的行为,而切点则定义了这些行为何时触发。 二、spring-aop.jar组件解析 1. **AOP代理**:Spring AOP支持两种代理...

Global site tag (gtag.js) - Google Analytics