Spring总结3—AOP
来源:互联网 发布:淘宝客点击要钱吗 编辑:程序博客网 时间:2024/06/05 14:07
一、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/aophttp://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>
- Spring总结3—AOP
- Spring总结之一 —— AOP
- Spring学习总结(9)——Spring AOP总结
- Spring总结之AOP
- Spring总结之AOP
- Spring总结-AOP
- spring AOP学习总结
- Spring AOP 学习总结
- Spring Aop机制总结
- Spring AOP总结
- spring aop实现总结
- Spring AOP总结
- Spring Aop总结
- Spring Aop基础总结
- Spring/Aop代码总结
- Spring AOP总结
- Spring AOP总结
- Spring AOP总结
- Intellij 打包WEB应用程序
- android studio导入jar 后产生的 gradle 错误
- C语言
- 用字符串做一个文本编译器
- 用Disk Genius检测和修复硬盘坏道
- Spring总结3—AOP
- 开源Easydarwin流媒体服务器Windows编译、配置、部署
- Android中的Handler分析
- 【饥荒mod制作吧第三篇】本吧友情贴吧传送门
- 求直线与平面的交点
- poj 1258 Agri-Net
- beautifulsoup介绍和安装
- Android发展以及历史版本号
- 【基础知识】——构造函数