2. AOP 底层技术实现 小风 Java 实战系列教程 关键词 : 代理模式 代理模型分为两种 : 1) 接口代理 (JDK 动态代理 ) 2) 子类代理 (Cglib 子类代理 ) 需求 :CustomerService 业务类, 有 save,update 方法, 希望在 save,updat

Save this PDF as:
 WORD  PNG  TXT  JPG

Size: px
Start display at page:

Download "2. AOP 底层技术实现 小风 Java 实战系列教程 关键词 : 代理模式 代理模型分为两种 : 1) 接口代理 (JDK 动态代理 ) 2) 子类代理 (Cglib 子类代理 ) 需求 :CustomerService 业务类, 有 save,update 方法, 希望在 save,updat"

Transcription

1 本章学习目标 小风 Java 实战系列教程 AOP 思想概述 AOP 底层技术实现 AOP 术语介绍 SpringAOP 的 XML 方式 HelloWorld SpringAOP 的 XML 方式配置细节 SpringAOP 的注解方式 SpringAOP 的零配置方式 1. AOP 思想概述 1.1. AOP 思想简介 1.2. AOP 的作用

2 2. AOP 底层技术实现 小风 Java 实战系列教程 关键词 : 代理模式 代理模型分为两种 : 1) 接口代理 (JDK 动态代理 ) 2) 子类代理 (Cglib 子类代理 ) 需求 :CustomerService 业务类, 有 save,update 方法, 希望在 save,update 方 法执行之前记录日志 2.1. 接口代理 (JDK 动态代理 ) public class JDKProxyUtils { /** * 使用 JDK 动态代理获取代理对象 * target: 目标对象 */ public static Object getproxy(final Object target){ return Proxy.newProxyInstance( target.getclass().getclassloader(), // 和目标对象一样的 类加载器 target.getclass().getinterfaces(), // 目标对象的接口列表 new InvocationHandler() { //invoke:

3 public Object invoke(object proxy, Method method, Object[] args) throws Throwable { System.out.println(" 记录日志 "); // 调用目标对象的方法 return method.invoke(target, args); ); 注意 :JDK 动态代理必须是基于接口的代理! 如果目标对象没有接口, 那么只能子类代理! 2.2. 子类代理 (Cglib 方式 ) 导入 cglib 的 jar 包 编写 Cglib 子类代理代码 public class CglibProxyUtils { /**

4 * 使用 Cglib 工具创建目标对象的子类对象 target */ public static Object getproxy(final Object target){ return Enhancer.create(CustomerServiceImpl2.class, new MethodInterceptor() { //intercept: public Object intercept(object arg0, Method method, Object[] arg2, MethodProxy arg3) throws Throwable { System.out.println(" 记录日志 "); // 调用目标对象的方法 return method.invoke(target, arg2); ); 3. AOP 术语介绍 1) 目标对象 (Target) 2) 代理对象 (Proxy) 3) 连接点 (Joinpoint) 4) 切入点 (Pointcut) 5) 通知 ( 增强 )(Advice) 6) 切面 (Aspect Advisor)

5 7) 织入 ( 切入 )(weaving) 小风 Java 实战系列教程 4. SpringAOP 的 XML 方式 4.1. HelloWolrd 入门程序 导入 spring 的 aop 相关 jar 包 注意 : 使用了 aspectj 插件, 作用是简化 Spring 的 XML 方式 AOP 编程

6 编写目标类 ( 有接口的情况 ) /** * 目标对象 lenovo * */ public class CustomerServiceImpl implements CustomerService public void save() { System.out.println(" 执行 save 方法 public void update() { System.out.println(" 执行 update 方法 ");

7 编写切面类 小风 Java 实战系列教程 /** * Spring 的 AOP 的切面类 lenovo * */ public class MyAspect1 { /** * 通知方法 */ public void log(){ System.out.println(" 使用 spring 的 AOP 切入日志..."); 编写 applicationcontext.xml( 重点 ) 引入 aop 新的名称空间 : <?xml version="1.0" encoding="utf-8"?> <beans xmlns=" xmlns:p="

8 xmlns:aop=" xmlns:xsi=" xsi:schemalocation=" <!-- spring 的 AOP 编写 -- XML 方式 --> <!-- 1. 创建目标对象 --> <bean id="customerservice" class="cn.sm1234.service.impl.customerserviceimpl"/> <!-- 2. 创建切面类对象 --> <bean id="myaspect1" class="cn.sm1234.apsect.myaspect1"/> <!-- 3. 配置 AOP 切面 --> <aop:config> <!-- 切面 = 通知 + 切入点 --> <aop:aspect ref="myaspect1"> <aop:before method="log" pointcut-ref="pt"/> <aop:pointcut expression="execution(public void cn.sm1234.service.impl.customerserviceimpl.*())" id="pt"/> </aop:aspect> </aop:config> </beans>

9 编写测试代码 小风 public class Demo1 private CustomerService public void test1(){ customerservice.save(); customerservice.update(); 4.2. SpringAOP 的 XML 配置细节 切入点表达式 <aop:config> <aop:aspect ref="myaspect1"> <aop:before method="log" pointcut-ref="pt"/> <!-- 切入点表达式的语法 1. execution(): 代表切入方式, 固定语法 2. public: 方法的修饰符, 通常为 public 方法 3. void: 方法的返回值 可以使用通配符 : * 4. cn.sm1234.service.impl: 类所在的包

10 4.1 可以使用通配符 : * (* 只能匹配一级目录 ) 4.2 可以使用 *..* 匹配任意级目录 5.CustomerServiceImpl: 类名称 5.1 可以使用通配符 : * ( 匹配任意字符 ) 6. save() : 代表方法 6.1 可以使用通配符 : * ( 匹配任意字符 ) 7. 方法的参数 7.1 可以使用通配符 :.. ( 匹配任何参数类型的方法 ) --> <aop:pointcut expression="execution(public * cn.sm1234.*..*.*serviceimpl.*(..))" id="pt"/> </aop:aspect> </aop:config> 通知类型 前置通知 在方法的前面执行 最终通知 在方法的最后执行, 无论方法是否出现异常, 通知都会被执行 后置通知 在方法的最后执行, 只有在方法成功执行之后才被执行

11 异常通知 在方法出现异常的时候执行 环绕通知 在方法的前后执行 <aop:config> <aop:aspect ref="myaspect1"> <!-- <aop:before method="before" pointcut-ref="pt"/> --> <!-- <aop:after method="after" pointcut-ref="pt"/> --> <!-- <aop:after-returning method="afterreturning" pointcut-ref="pt"/> --> <!-- <aop:after-throwing method="afterthrowing" pointcut-ref="pt"/> --> <aop:around method="around" pointcut-ref="pt"/> <aop:pointcut expression="execution(public * cn.sm1234.service.impl.customerserviceimpl.*(..))" id="pt"/> </aop:aspect> </aop:config>

12 5. SpringAOP 的注解方式 小风 Java 实战系列教程 5.1. HelloWorld 的入门程序 导入 spring 的 aop 相关 jar 包 注意 : 使用了 aspectj 插件, 作用是简化 Spring 的 XML 方式 AOP 编程 编写目标类 ( 有接口的情况 ) /** * 目标对象 lenovo * */

13 public class CustomerServiceImpl implements CustomerService { 小风 Java public void save() { System.out.println(" 执行 save 方法 public void update() { System.out.println(" 执行 update 方法 "); 编写切面类, 添加切面相关的注解 /** * 注解版本的切面类 lenovo * public class MyAspect * cn.sm1234.service.impl.customerserviceimpl.*.(..))") public void log(){ System.out.println(" 记录日志 ");

14 编写 applicationcontext.xml( 重点 ) 引入 aop 新的名称空间 : <?xml version="1.0" encoding="utf-8"?> <beans xmlns=" xmlns:p=" xmlns:aop=" xmlns:xsi=" xsi:schemalocation=" <!-- spring 的 AOP 编写之注解方式 --> <!-- 1. 创建目标对象 --> <bean id="customerservice" class="cn.sm1234.service.impl.customerserviceimpl"/> <!-- 2. 创建切面类对象 -->

15 <bean id="myaspect" class="cn.sm1234.apsect.myaspect"/> 小风 Java 实战系列教程 <!-- 3. 开启 AOP 切面注解 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans> public class Demo1 private CustomerService public void test1(){ customerservice.save(10); = "execution(public * cn.sm1234.service.impl.customerserviceimpl.*(..))") public void before() { System.out.println(" 执行前置通知..."); // 最终通知

16 @After(value = "execution(public * cn.sm1234.service.impl.customerserviceimpl.*(..))") public void after() { System.out.println(" 执行最终通知..."); // = "execution(public * cn.sm1234.service.impl.customerserviceimpl.*(..))") public void afterreturning() { System.out.println(" 执行后置通知..."); // = "execution(public * cn.sm1234.service.impl.customerserviceimpl.*(..))") public void afterthrowing() { System.out.println(" 执行异常通知..."); // = "execution(public * cn.sm1234.service.impl.customerserviceimpl.*(..))") public void around(proceedingjoinpoint jp) { System.out.println(" 前面执行的代码..."); // 执行目标的方法

17 try { jp.proceed(); catch (Throwable e) { e.printstacktrace(); System.out.println(" 后面执行的代码..."); 6. SpringAOP 的零配置方式 /** * Spring 配置类 lenovo @EnableAspectJAutoProxy // 开启 AOP 注解功能 public class public class Demo1 private CustomerService customerservice;

18 @Test public void test1(){ customerservice.save(10); customerservice.update();