Spring AOP-1 Spring AOP入门
来源:互联网 发布:中国国玺云计算 编辑:程序博客网 时间:2024/06/10 00:12
什么是AOP
AOP(Aspect-OrientedProgramming,面向方面编程)。
在我们的代码中,像日志,事务,安全等模块会散步在很多的业务代码中,这些模块称为“横切关注点”。
横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。
这些横切关注点与业务代码的核心功能无关,但是却大量存在,导致了大量代码的重复。
AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
AOP相关概念
- 切面(Aspect):通知与切点的结合。用Spring的Advisor实现。
- 连接点(Joinpoint): 程序执行过程中明确的点,如方法的调用或特定的异常被抛出。
- 通知(Advice): 即在调用方法时需要执行的动作,Spring定义了5种通知:前置通知,后置通知,返回通知,异常通知和环绕通知。
- 切入点(Pointcut): 指定一个通知将被引发的一系列连接点的集合。
如何使用Spring AOP
Spring提供了4种方式实现AOP:
1. 配置ProxyFactoryBean,显式地设置advisors, advice, target等
2. 配置AutoProxyCreator,这种方式下,还是如以前一样使用定义的bean,但是从容器中获得的其实已经是代理对象
3. 通过来配置
4. 通过来配置,使用AspectJ的注解来标识通知及切入点
AOP现有两个主要的流行框架,即Spring AOP和Spring+AspectJ
下面来看具体的代码实现。
方式一 在XML中声明切面
1. 首先定义一个切面类:
package com.wgs.aspect;/** * Created by GenshenWang.nomico on 2017/7/8. */public class TrsactionAspect { public void beforeMethod(){ System.out.println("before:事务开始了==========="); } public void afterMethod(){ System.out.println("after:事务结束了==========="); }}
2. 需要在springmvc的配置文件中去显示的声明这个切面:
<bean id="transactionAspect" class="com.wgs.aspect.TrsactionAspect"/> <aop:config> <aop:pointcut id="pointcut" expression="execution(* com.wgs.controller.IndexController2.*(..))"/> <aop:aspect ref="transactionAspect" order="1"> <aop:before method="beforeMethod" pointcut-ref="pointcut"/> <aop:after method="afterMethod" pointcut-ref="pointcut"/> </aop:aspect> </aop:config>
注:必须在springmvc的配置文件中去声明,否则会报异常。
原因在于:
若将其配置在了spring.xml 核心配置文件中,该配置文件会被ContextLoaderListenerclass加载,Spring会创建一个WebApplicationContext上下文,称为父上下文(父容器) ,保存在 ServletContext中,keyWebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的值。
而spring-mvc.xml是DispatcherServlet,可以同时配置多个,每个 DispatcherServlet有一个自己的上下文对象(WebApplicationContext),称为子上下文(子容器),子上下文可以访问父上下文中的内容,但父上下文不能访问子上下文中的内容。 它也保存在 ServletContext中,key是”org.springframework.web.servlet.FrameworkServlet.CONTEXT”+Servlet名称
当spring加载父容器的时候就会去找切入点,但是这个时候切入的controller是在子容器中的,父容器是无法访问子容器,所以就拦截不到。
如果将上述的配置文件放到spring-mvc.xml中,那么问题就解决了。
3. 测试:
@Controllerpublic class IndexController { @ResponseBody @RequestMapping(value="/index", method = {RequestMethod.GET}) public void index(){ System.out.println("我要工作啦。。。"); }}
输出:
before:事务开始了===========
我要工作啦。。。
after:事务结束了===========
方式二 使用AspectJ注解的方式
1. 通过注解声明一个切面类:
package com.wgs.aspect;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.springframework.stereotype.Component;/** * Created by GenshenWang.nomico on 2017/7/8. */@Aspect@Componentpublic class LogAspect { //定义切点 @Pointcut("execution(* com.wgs.controller.IndexController.*(..))\"") private void pointCut(){} //前置通知 @Before("pointCut()") public void beforeMethod(){ System.out.println("before:日志开始记录了==========="); } //后置通知 @After("pointCut()") public void afterMethod(){ System.out.println("after:日志记录结束了==========="); } //声明返回通知 @AfterReturning(pointcut = "pointCut()", returning = "result") public void doAfterReturning(String result) { System.out.println("后置通知"); System.out.println("---" + result + "---"); } // 声明异常通知 @AfterThrowing(pointcut = "pointCut()", throwing = "e") public void doAfterThrowing(Exception e) { System.out.println("异常通知"); System.out.println(e.getMessage()); } //声明环绕通知 @Around("pointCut()") public Object doAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("进入方法---环绕通知"); Object o = pjp.proceed(); System.out.println("退出方法---环绕通知"); return o; }}
2. 要想使用AspectJ,需要在切面类上加上@EnableAspectJAutoProxy 或者在SpringMVCd的配置文件中加上 <aop:aspectj-autoproxy proxy-target-class="true"/>
来启用AspectJ的自动代理。
3. 测试
@ResponseBody @RequestMapping(value="/index2", method = {RequestMethod.GET}) public void index(){ System.out.println("我要工作啦。。。"); }
输出:
进入方法—环绕通知
before:日志开始记录了===========
我要工作啦。。。
退出方法—环绕通知
after:日志记录结束了===========
进入方法—环绕通知
before:日志开始记录了===========
我要工作啦。。。
退出方法—环绕通知
after:日志记录结束了===========
两种方法比较
1、织入的时期不同
Spring Aop采用的动态织入,而Aspectj是静态织入。
静态织入:指在编译时期就织入,即:编译出来的class文件,字节码就已经被织入了。
动态织入又分静动两种,静则指织入过程只在第一次调用时执行;动则指根据代码动态运行的中间状态来决定如何操作,每次调用Target的时候都执行。
2、从使用对象不同
Spring AOP的通知是基于该对象是SpringBean对象才可以,而AspectJ可以在任何Java对象上应用通知。
Spring AOP:如果你想要在通过this对象调用的方法上应用通知,那么你必须使用currentProxy对象,并调用其上的相应方法;于此相似,如果你想要在某对象的方法上应用通知,那么你必须使用与该对象相应的Spring bean
AspectJ:使用AspectJ的一个间接局限是,因为AspectJ通知可以应用于POJO之上,它有可能将通知应用于一个已配置的通知之上。对于一个你没有注意到这方面问题的大范围应用的通知,这有可能导致一个无限循环。
参考:http://blog.csdn.net/a128953ad/article/details/50509437
- Spring AOP-1 Spring AOP入门
- spring aop入门1
- Spring AOP入门篇
- Spring AOP入门
- Spring AOP 入门实例
- Spring AOP 入门
- Spring AOP 入门(2)
- Spring AOP 入门实例
- Spring AOP 入门学习
- Spring AOP 入门学习
- spring AOP 入门
- Spring AOP入门
- spring AOP 入门实例
- spring aop入门例子
- Spring AOP入门
- Spring 入门 AOP
- Spring 入门 AOP
- spring aop 注解入门
- 缓存第三篇:redis入门之下载安装和命令行使用
- [刷题]Codeforces 816B
- 神奇的伽玛函数(上)
- volatile
- (九)监控模块-monitor
- Spring AOP-1 Spring AOP入门
- GeoHash算法原理及实现方式
- list、tuple和dict以及set详细讲解
- 如何定义一个只能在堆(栈)上生成对象的类
- Tengine(编译)安装示例
- 解决使用NAT连接的linux可以上网,但是ping不通问题
- 持续集成之jenkins实践教程:基础篇(2): 集成gitlab
- html标签
- 返回值与输出参数比较(return value or out parameter)