Spring 框架的核心功能之AOP技术
2017-10-23 23:31
716 查看
1. AOP 的概述
- AOP, Aspect Oriented Programming, 面向切面编程;
- 通过预编译方式和运行期动态代理实现程序功能的统一维护的技术;
- AOP 采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视,事务管理,安全检查,缓存);
- AOP 可以在不修改源代码的前提下,对程序进行增强;
2. AOP 的底层实现
- Spring 框架的AOP技术底层采用的是代理技术,代理方式分为:
-
基于JDK的动态代理:必须是面向接口的,只有实现了具体接口的类才能生成代理对象;
- 基于CGLIB的动态代理: 对于没有实现接口的类,采用生成类的子类的方式;
- 基于JDK的动态代理的原理,请参考"动态代理入门"
- 基于CGLIB的代理技术(了解)
// 1. 引入Spring 核心开发包, 其中包含CGLIB的开发 jar包, // 2. 编写相关代码 // CGLIB 代理类 public class MyCglibUtils{ public static BookDaoImpl getProxy(){ // 创建 CGLIB 的核心类 Enhancer enhancer = new Enhancer(); // 设置父类 enhancer.setSuperclass(BookDaoImpl.class); // 设置回调函数, 参数为匿名内部类 enhancer.setCallback(new MethodInterceptor(){ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable{ if("save".equals(method.getName())){ // 添加新功能(例如记录日志) System.out.println("开始记录日志..."); } // 目标对象的方法正常执行 return methodProxy.invokeSuper(obj,args); } }); // 生成代理对象 BookDaoImpl proxy = (BookDaoImpl)enhancer.create(); return proxy; } } public class BookDaoImpl{ public void save(){ System.out.println("保存图书..."); } } // 测试方法 public class Demo{ // 没有使用代理之前 public void fun2(){ BookDaoImpl dao = new BookDaoImpl(); dao.save(); } // 使用CGLIB代理 public void fun3(){ BookDaoImpl proxy = MyCglibUtils.getProxy(); proxy.save(); } }
3. Spring 基于AspectJ的AOP开发
1. AOP 的相关术语
Joinpoint(连接点)
: 指那些被拦截到的点,在Spring中,这些点指的是类中的所有方法;Pointcut(切入点)
: 指我们要对哪些Joinpoint进行拦截,也就是需要增强的方法;Advice(通知/增强)
: 指拦截到Joinpoint之后,所要做的事情,分为前置通知,后置通知,异常通知,最终通知,环绕通知;Introduction(引介)
: 是一种特殊的通知; 在不修改类代码的前提下,introduction 可以在运行期为类动态的
添加一些方法或Field;Target(目标对象)
: 代理的目标对象;Weaving(织入)
:是指把增强添加到目标对象,创建新的代理对象的过程;Proxy(代理)
: 一个类被AOP织入增强后,就产生一个结果代理类;Aspect(切面)
: 是切入点和通知的结合;- 其中,通知需要自己来编写,切入点需要自己来配置;
2. AspectJ的XML方式完成AOP的开发
2.1 导入 jar 包
- Spring 框架的基本开发包(6个);
- Spring 的传统AOP的开发包
spring-aop-4.3.10.RELEASE
org.aopalliance-1.10.0
(在 Spring 依赖包中)
org.aspectj.weave-1.6.8.RELEASE.jar(在 Spring 依赖包中)
spring-aspects-4.3.10.RELEASE.jar
2.2 编写 applicationContext.xml 配置文件
// 需要引入具体的AOP的schema约束 <?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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 配置 customerDao --> <bean id="customerDao" class="cn.itcast.demo.CustomerDaoImpl"/> <!-- 配置切面类 --> <bean id="myAspectXml" class="cn.itcast.demo.MyAspectXml"/> <!-- 配置 AOP --> <aop:config> <!-- 配置切面类: 包含了切入点和通知(类型) --> <aop:aspect ref="myAspectXml"> <!-- 配置前置通知 --> <!-- 切入点表达式: execution(public void cn.itcast.demo.CustomerDaoImpl.save()) --> <aop:before method="log" pointcut="execution(public void cn.itcast.demo.CustomerDaoImpl.save())"/> </aop:aspect> </aop:config> </beans>
2.3 创建包结构,编写具体的接口和实现类
cn.itcast.demo
CustomerDao
: 接口CustomerDaoImpl
: 实现类
// CustomerDao.java 接口 public interface CustomerDao{ public void save(); public void update(); } // CustomerDaoImpl.java 实现类 public class CustomerDaoImpl implements CustomerDao{ public void save(){ System.out.println("保存客户..."); } public void update(){ System.out.println("修改客户..."); } } // 测试类 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public void Demo{ @Resource(name="customerDao") private CustomerDao customerDao; @Test public void fun(){ customerDao.save(); customerDao.update(); } } // 需求: 使用AOP技术,在不改变源代码的情况下,增强 save() 方法 // 创建切面类 public class MyAspect{ // 通知(具体的增强) public void log(){ System.out.println("记录日志..."); } } // 然后在 applicationContext.xml 中配置切面类, 即可完成增强
3. AOP 的切入点表达式
- 格式:
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
-
修饰符 public 可以省略不写;
- 返回值类型不能省略的,可以使用 * 代替,表示返回值为任意类型;
- 包名,以
cn.itcast.demo.CustomerDaoImpl.save()
为例cn
是不能省略的,可以使用 * 代替; - 中间的包名可以使用 * 代替;
- 如果向省略掉中间的包名,可以使用"..",表示任意包下的 save 方法;
- 类名可以使用 * 代替,也有类似的写法
*DaoImpl
; - 方法可以使用 * 代替,也有类似的写法
save*()
- 参数如果是一个参数可以使用 * 代替,如果向代表任意参数,可以使用".."
4. AOP 的通知类型
- 前置通知
-
在目标类的方法执行之前执行;
- 具体配置格式:
<aop:before method="方法名" pointcut="被增强的方法"/>
- 应用: 可以对方法的参数来做校验;
- 最终通知
-
在目标类的方法执行之后执行,如果程序出现了异常,最终通知也会执行;
- 具体配置格式:
<aop:after method="方法名" pointcut="被增强的方法"/>
- 应用:释放资源;
- 后置通知
-
方法正常执行后的通知;
- 具体配置格式:
<aop:after-returning method="方法名" pointcut="被增强的方法"/>
- 应用: 可以修改方法的返回值;
- 异常抛出通知
-
在抛出异常后的通知;
- 具体配置格式:
<aop:after-throwing method="方法名" pointcut="被增强的方法"/>
- 应用:包装异常信息;
- 环绕通知
-
方法的执行前后执行;
- 具体配置格式:
<aop:around method="方法名" pointcut="被增强的方法"/>
- 默认情况下,目标对象的方法不能执行,需要手动让目标对象的方法执行;
// 环绕通知的增强方法 public void around(ProceedingJoinPoint joinPoint){ System.out.println("环绕通知1...."); // 手动执行目标方法 try{ joinPoint.proceed(); }catch(Exception e){ throw new RuntimeException(e); } System.out.println("环绕通知2...."); }
参考资料
相关文章推荐
- SSH集成框架下真正实现Spring AOP拦截功能
- Spring 技术核心 IOC AOP <二> AOP详解
- [置顶] Spring3核心技术之AOP配置
- (七)Spring核心框架 - AOP的起源及介绍
- (九)Spring核心框架 - AOP之动态代理机制
- AOP: Spring3核心技术之AOP配置
- Spring核心技术之Ioc和AOP
- Spring核心技术--AOP
- spring使用AOP技术对DAO层操作进行增强功能
- 框架学习之Spring 第三节 采用Spring实现AOP功能
- Spring核心技术阐述(IOC、DI、AOP)
- Spring核心技术阐述(IOC、DI、AOP)
- Spring核心技术原理-(2)-通过Web开发演进过程了解一下为什么要有Spring AOP?
- 分析Spring启动过程,完成实现核心的两大功能(IOC , AOP);
- 【框架】[Spring]纯Java的方式实现AOP切面(拦截)技术
- Spring核心框架 - AOP之动态代理机制
- JAVA 中web 框架Spring 的核心 aop 和ioc
- Spring核心框架 - AOP的原理及源码解析
- Spring3核心技术之AOP配置
- Spring核心技术原理-(2)-通过Web开发演进过程了解一下为什么要有Spring AOP?