标签:style blog class code c java
(以下内容来自百度百科)
面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。是软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
很多人在初次接触 AOP 的时候可能会说,AOP 能做到的,一个定义良好的 OOP 的接口也一样能够做到,我想这个观点是值得商榷的。AOP和定义良好的 OOP 的接口可以说都是用来解决并且实现需求中的横切问题的方法。但是对于 OOP 中的接口来说,它仍然需要我们在相应的模块中去调用该接口中相关的方法,这是 OOP 所无法避免的,并且一旦接口不得不进行修改的时候,所有事情会变得一团糟;AOP 则不会这样,你只需要修改相应的 Aspect,再重新编织(weave)即可。 当然,AOP 也绝对不会代替 OOP。核心的需求仍然会由 OOP 来加以实现,而 AOP 将会和 OOP 整合起来,以此之长,补彼之短。
主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改
变这些行为的时候不影响业务逻辑的代码
AOP是一个概念,并没有设定具体语言的实现,它能克服那些只有单继承特性语言的缺点(如Java),目前AOP具体实现有以下几个项目:
AspectJ (TM): 创建于Xerox PARC. 有近十年历史,成熟
缺点:过于复杂;破坏封装;需要专门的Java编译器。动态AOP:使用JDK的动态代理API或字节码Bytecode处理技术
Spring对AOP编程提供了丰富的支持,是spring的两大核心(IOC和AOP)之一。Spring中的AOP是用java来实现的,在spring3.2.5官方文档对于AOP Proxies的描述如下:
1、Spring中默认使用标准的J2EE动态代理来生成AOP代理,这使得任何实现接口(或者一组接口)的类可以被代理。
2、Spring中的AOP也使用CGLIB代理,被代理的类必须是一个类而且是没有实现任何接口的。如果一个类没有实现接口,那么这样的类就可以用CGLIB来实现代理。
注:在Spring3.2.5中Spring-core中默认加入了CGLIB这个jar包,不需要自己再添加jar包了。如果要改变生成类的方式可以用如下的配置:proxy-target-class=‘true’
<aop:aspectj-autoproxy proxy-target-class="true" />
好了说了这么多的概念性的东西,来看代码吧
请看下面的类图 :
这是一个很简单的model2框架,里出全是业务实现代码并没有其它功能(里的类的注入用的是SpringIOC)。如果你想给某天对这个项目进行修改、重构的时候想在saveUser()的前后添加日志记录怎么办?
可以新手最先想到的是:直接添加不就行了。但是这是一个类,如果在以后的项目中10或者20个这样的类应该怎么做?你还要一个一个类的打开进行复制、修改。想想这都是一个噩梦!
我们可以把所有对数据库保存的方法就是以save*开头的方法当成一个切面对方法前后添加记录日志的功能。
以下代码在Myeclipse2013和JDK1.7 Spring3.2.5、JUnit4中测试通过
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 启用Annotation配置 --> <context:annotation-config /> <!-- 告诉spring要扫描那个包下的类 --> <context:component-scan base-package="com.zxd"></context:component-scan> <!-- 启用AspectJ对Annotation的支持 --> <!-- 从Spring3.2开始在Spring-core中默认加入了CGLIB这个jar包,不需要自己再添加jar包了 proxy-target-class=‘true’ 改变生成代理的方式 --> <aop:aspectj-autoproxy proxy-target-class="true" /> <!-- Spring AOP,如果不强制使用CGLIB包,默认情况是使用JDK的动态代理来代理接口。 --> <!-- 启用AspectJ支持 如果不使用XML Schema配置方式,可以使用在配置文件中添加以下的内容 --> <!-- <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" /> --> </beans>
注:请注意要先引用命名空间。
LogInterceptor .java
package com.zxd.aop; import java.util.Arrays; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * 这个类是用来进行测试Spring的AOP切面类 * * @author zhang * */ @Aspect @Component public class LogInterceptor { // 声明一个切入点 @Pointcut("execution(* com.zxd.service..*.add(..))") public void actionMethod() { }; /* * 使用Before增强处理,通常要指定一个value值,用来指定切入点 这个增强处理发生在目标方法执行之前织入执行 注:无法访问目标方法的返回值 */ @Before("actionMethod()") public void addLog() { System.out.println("添加日志"); } @After("actionMethod()") public void overLog2() { System.out.println("添加日志结束"); } }
DAO层对应的实现类
UserDAOImpl.java
package com.zxd.dao.impl; import org.springframework.stereotype.Component; import com.zxd.dao.UserDAO; import com.zxd.model.User; //默认使用类名首字母小写 @Component("userDAO") public class UserDAOImpl implements UserDAO { public void save(User user) { //Hibernate //JDBC //XML //NetWork System.out.println("user saved!"); } }
JUnit测试类 test.java
package com.zxd.test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.zxd.model.User; import com.zxd.service.UserService; //Dependency Injection //Inverse of Control public class UserServiceTest { @Test public void testAdd() throws Exception { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); UserService us = context.getBean("userService",UserService.class); us.add(new User()); } }
打印结果如下:
/* * 对于AfterReturning增强处理的说明 这个增强处理会在目标方法执行完成后被织入执行 * returning:指定一个返回值的形参名,增强处理定义的方法可以通过该形参名来访问目标方法的返回值 * 注:AfterReturning还可以限定切入点的只匹配具有对应返回值类型的方法可以过滤一些其它返回值类型的方法 * 虽然AfterReturning可以访问目标参数的方法,但是不能改变目标方法的返回值 */ /* @AfterReturning(pointcut = "actionMethod()", returning = "rvt") public void log(Double rvt) { System.out.println("获得目标方法的返回值:" + rvt); System.out.println("AferReturning方法执行》》》》》》》"); }
如果在一个目标对象的方法里有两个增强处理对这个方法进行了拦截那么Spring是如何对这个顺序进行排序的呢?
Spring采用和AspectJ一样的优先顺序来织入增强处理在“进入时”(Before)优先级高的先被织入,在“退出”(After)时, * 优先级高的会被后织入 Spring提供了如下两种方案来解决处理程序的优先级问题:
1、让切面类来实现org.springframework.core.Ordered接口,实现该接口只需要实现一个 int getOrder()方法, 该方法的返回值越小,则优先级越高
2、直接使用@Order Annotation来修饰一个切面类,里面指定一个int类型的值,值越小优先级越高,比如:@Order(2)
注:在before时优先级越高先进行织入,如果在After之后优先级越高越在最后进行织入。
XML代码如下:
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 启用Annotation配置 --> <context:annotation-config /> <!-- 告诉spring要扫描那个包下的类 --> <context:component-scan base-package="com.zxd"></context:component-scan> <bean id="log" class="com.zxd.aop.LogInterceptor"></bean> <!-- XML中对于AOP的配置 --> <aop:config> <!-- 声明一个切点 --> <aop:pointcut expression="execution(* com.zxd.service..*.test(..))" id="logPoint" /> <!-- 定义切面类中的具体操作 --> <aop:aspect ref="log" id="logAspect"> <!-- 定义一个before处理 --> <aop:before method="before" pointcut-ref="logPoint" /> </aop:aspect> </aop:config> </beans>
标签:style blog class code c java
原文地址:http://www.cnblogs.com/zxdBlog/p/3734868.html