Spring总结3—AOP
2016-04-24 17:45
567 查看
一、AOP概念及原理
1、AOP概念:定义:将程序中的交叉业务逻辑提取出来,称之为切面。将这些切面动态织入到目标对象,然后生成一个代理对象的过程。
AOP(Aspect-Oriented Programming,面向切面编程)是一种程序设计思想,该思想的主要目标是将系统分为两部分:一部分封装了系统中各组件的通用功能(罗辑或者责任),形成一个切面,该切面被称为应用系统的”横切关注点”,此部分包含了与系统核心商业逻辑关系不大的部分;系统的其余部分,即核心商业逻辑部分,被称为系统的”核心关注点”,此部分包含了系统中业务处理的主要流程。其中,”横切关注点”经常出现在”核心关注点”的周围,但无论出现在何处,它们的基本功能是相似的,比如权限认证、日志、事务处理等。
2、面向切面编程思维的好处
一方面可以使我们在系统开发过程中的责任分工更为明确(比如,可以让高级工程师负责”横切关注点”的开发,初级工程师负责”核心关注点”的开发,配置工程师负责将以上两部分搭建成一个完整的应用系统);另一方面,清晰的系统结构将使我们以后的系统维护工作变得更为轻松。
总述:可以动态的添加和删除在切面上的逻辑而不影响原来的执行代码。
3、工作原理—动态代理
动态代理原理:动态代理原理其实就是反射+多态+聚合的实现。JDK 5引入的动态代理机制,允许开发人员在运行时刻动态的创建出代理类及其对象。在运行时刻,可以动态创建出一个实现了多个接口的代理类。每个代理类的对象都会关联一个表示内部处理逻辑的InvocationHandler接 口的实现。当使用者调用了代理对象所代理的接口中的方法的时候,这个调用的信息会被传递给InvocationHandler的invoke方法。在 invoke方法的参数中可以获取到代理对象、方法对应的Method对象和调用的实际参数。invoke方法的返回值被返回给使用者。这种做法实际上相 当于对方法调用进行了拦截。
具体实现案例:
创建代理器,让其实现InvocationHandler接口
public class LogInterceptor implements InvocationHandler{ //log日志要添加一个目标 private Object target; public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } public void beforeMethod(Method method){ System.out.println(method.getName()+"start!"); } public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { beforeMethod(method); method.invoke(target, args); return null; } }
测试该代理类:关键是Proxy.newProxyInstance()里面有3个参数,分别是被代理目标对象的ClassLoader,被代理目标对象实现的接口,InvocationHandler类型的代理器。
public void testProxy(){ //代理的目标对象(面向抽象编程:UserDAOPImpl()是抽象类UserDAP的实现类) UserDAO userDAO = new UserDAOImpl(); //代理器(实现了InvocationHandler接口) LogInterceptor log = new LogInterceptor(); //在代理器中注入代理对象 log.setTarget(userDAO); //执行代码任务,转换成目标对象 UserDAO userDAOProxy = (UserDAO)Proxy.newProxyInstance(userDAO.getClass().getClassLoader(),userDAO.getClass().getInterfaces(), (InvocationHandler) log); System.out.println(userDAOProxy.getClass()); //调用目标对象的方法,(保存用户) userDAOProxy.save(new User()); }
AOP采用动态代理的过程:
将切面使用动态代理的方式动态织入到目标对象(被代理类),形成一个代理对象;
目标对象如果没有实现代理接口,那么Spring会采用CGLib生成代理对象,该代理对象是目标对象的子类;
目标对象是final类的并且也没有实现代理接口的,就不能运用AOP
二、AOP基础知识
a)JoinPoint(连接点)连接点,指切面可以织入到目标对象的位置(方法,属性等).例如类中的一个方法。它是一个抽象的概念,在实现AOP时,并不需要去定义一个Join point。
b)PointCut(切入点)
切入点,指通知应用到哪些类的哪些方法或属性之上的规则。本质上是一个捕获连接点的结构(或称连接点的集合)。在AOP中,可以定义一个Point cut,来捕获相关方法(通知中的逻辑)的调用。
c)Aspect(切面)
Point cut和Advice的组合,它类似于OOP中定义的一个类,但它代表的更多的是对象间横向的关系。
d)Advice(通知)
Point cut的执行代码,它是执行”切面”的具体逻辑。
e)Target(目标对象)
指需要织入切面的对象。包含Join point的对象,它是被Advice的类,也是商务逻辑对象。这个对象永远是一个被代理的对象。
f)Weave(织入)
织入,指将通知插入到目标对象。将Aspec模块与核心商务逻辑(即目标对象)进行关联的过程,比如,将事务处理模块和银行柜员机程序通过配置结合起来,决定什么情况下事务处理模块被通知调用。
g)Proxy(AOP代理)
代理对象,指切面织入目标对象之后形成的对象。由AOP框架创建的对象,它是真正执行Advice的实体。
三、AOP配置—Annotation
1、xml文件中首先引入xmlns:aop=”http://www.springframework.org/schema/aop”以及其对应的xsi:schemaLocation。
2、再添加aop注解配置
<!--aop面向切面编程注解必须添加上下面的语句--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>下:
此时就可以解析对应的Annotation了。
配置文件代码如下:
<?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-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <!--注解annotation--> <context:annotation-config /> <!--Component:在类之上添加@Component注解,意味着是一个成员,默认名字是类名首字母小写,可以指定名字@Component("") 对于需注入的成员,添加@Resource(name=""),即可注入成功 @Service @Controller @Repository 与@Component相同意义。--> <context:component-scan base-package="com.cdd"/> <!--aop面向切面编程注解必须添加上下面的语句--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
3、建立我们的拦截类
4、用@Aspect注解这个类
拦截类就是我们要作为切面的那个类,即穿插到我们的业务逻辑中的类。比如监听或是打印日志
5、建立处理方法
拦截类中建立处理方法,具体方法的实现。
6、用@Before、@After、@AfterThrowing(“”)、@Around来注解对应的方法,规定该处理方法在切入点执行的位置
7、写明白切入点(execution …….)
对于每个方法的切入点都要进行规定。例如注释在某方法上@Before ,即表示:在织入点(execution)方法之前执行该方法
@Before("execution(public void com.cdd.dao.impl.UserDAOImpl.save(com.cdd.model.User))")//织入点到具体某个类的具有某个返回值的方法之前。
若织入点是某个包下的任意子包的具有任意返回值的任意方法 之前都执行该方法,织入点命名如下
@Before("execution(public * com.cdd..*.*(..))") public void before(){ System.out.println("method before!"); }
8、让spring对我们的拦截器类进行管理@Component
完整代码如下:
@Aspect //2.声明是一个切面
@Component //1.首先声明该类是个成员
public class LogInterceptor_AOP {
//a).@Before 在织入点方法(execution)之前执行该方法。
//@Before("execution(public void com.cdd.dao.impl.UserDAOImpl.save(com.cdd.model.User))")//3.织入点
//b)若在某包下的任意子包下的具有任意返回值的任意方法 之前都执行该方法,织入点命名如下
@Before("execution(public * com.cdd..*.*(..))") public void before(){ System.out.println("method before!"); }
//AfterReturning()是指织入点方法执行正常且完成后执行该方法
@AfterReturning("execution(public * com.cdd..*.*(..))")
public void afterReturn(){
System.out.println("after returning!");
}
//若每个方法的织入点相同,则可以将织入点定义为PointCut
@Pointcut("execution(public * com.cdd..*.*(..))")
public void myPointCut(){}
//@Around 环绕通知。环绕通知在一个方法执行之前和之后执行。它使得通知有机会 在一个方法执行之前和执行之后运行
//必须有ProceedingJoinPoint参数。执行pjp.proceed()方法
@Around("myPointCut()")
public void aroundMethod(ProceedingJoinPoint pjp){
System.out.println("pjp around before");
try {
pjp.proceed();
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("pjp around after");
}
//@AfterThrowing("")抛出异常通知在一个方法抛出异常后执行
//@After 不论一个方法是如何结束的,最终通知都会运行。通常用它来释放资源
}
四、AOP配置—xml
1、把interceptor对象初始化建立拦截类
public class LogInterceptor_XML { public void before(){ System.out.println("method before~!"); } }
2、xml配置,设置切面、切入点以及切入位置
<?xml version="1.0" encoding="UTF-8"?> <beans ...此处省略,与注解相同> <context:annotation-config /> <context:component-scan base-package="com.cdd" /> <bean id="logInterceptor" class="com.cdd.aop.LogInterceptor_XML"> </bean> <!--AOP xml配置--> <aop:config> <!--全局的PointCut --> <aop:pointcut expression="execution(public * com.cdd.service..*.add(..))" id="servicePointCut"/> <aop:aspect id="logAspect" ref="logInterceptor"> <!--有个before方法,其属性method:执行切面的哪个方法 织入点引用全局的,也可引用局部定义的,也可以直接指定pointcut--> <!--<aop:pointcut expression="execution(public * com.cdd.service..*.add(..))" id="logPointCut"/>--> <aop:before method="before" pointcut-ref="servicePointCut"/> </aop:aspect> </aop:config> </beans>
相关文章推荐
- javaGC机制之我见
- Spring官网下载dist.zip的几种方法
- 20145315 《Java程序设计》实验三实验报告
- java代理机制
- spring mvc CommonsMultipartResolver文件上传maxUploadSize限制大小
- java毕向东听课笔记25(集合框架-Set集合TreeSet)
- 【JavaSe】IO之FileReader
- java集合总结
- javaweb学习总结(二十)——JavaBean总结
- 实习面经--小米 java后台开发 v1
- 第04篇 JDK版本导致Unsupported major.minor version 52.0 error
- Spring Web MVC 入门分析
- springMVC 学习笔记
- Gradle学习系列之六——使用Java Plugin
- 正则的使用6
- JAVA集合框架之set
- 正则的使用5
- java ArrayList集合分析
- Java NIO系列教程(10):DatagramChannel
- java对象排序