AOP:面向切面、面向方面、面向接口是一种横切技术
横切技术运用:
1.事务管理: (1)数据库事务:(2)编程事务(3)声明事物:Spring AOP-->声明事物   
2.日志处理:
3.安全验证: Spring AOP---OOP升级

静态代理原理:目标对象:调用业务逻辑    代理对象:日志管理
表示层调用--->代理对象(日志管理)-->调用目标对象

动态代理原理:spring AOP采用动态代理来实现
(1)实现InvocationHandler接口

(2)创建代理类(通过java API)

Proxy.newProxyInstance(动态加载代理类,代理类实现接口,使用handler);

(3)调用invoke方法(虚拟机自动调用方法)

日志处理
 //调用目标对象
 method.invoke("目标对象","参数");
 日志处理

通过代理对象--(请求信息)-->目标对象---(返回信息)----> 代理对象

Spring 动态代理中的基本概念

1、关注点(concern)
   一个关注点可以是一个特定的问题,概念、或者应用程序的兴趣点。总而言之,应用程序必须达到一个目标
   安全验证、日志记录、事务管理都是一个关注点
   在oo应用程序中,关注点可能已经被代码模块化了还可能散落在整个对象模型中
2、横切关注点(crosscutting concern)
   如何一个关注点的实现代码散落在多个类中或方法中
3、方面(aspect)
   一个方面是对一个横切关注点模块化,它将那些原本散落在各处的,
   用于实现这个关注点的代码规整在一处
4、建议(advice)通知
   advice是point cut执行代码,是方面执行的具体实现
5、切入点(pointcut)
   用于指定某个建议用到何处
6、织入(weaving)
   将aspect(方面)运用到目标对象的过程
7、连接点(join point)
  程序执行过程中的一个点

通知类型:
  try{
    //前置通知
         //环绕通知
            //调用目标对象方法
         //环绕通知
    //后置通知
  }catch(){
    //异常通知
  }finally{
    //终止通知
  }

流程图

一.静态代理原理实例:

项目结构图:

IUserServ接口代码

  1. public interface IUserServ {
  2. List<User> findAllUser();
  3. int deleteUserById(User user);
  4. int saveUser(User user);
  5. }

UserServImpl实现类代码

  1. public class UserServImpl implements IUserServ {
  2. public int deleteUserById(User user) {
  3. System.out.println("******执行删除方法******");
  4. return 0;
  5. }
  6. public List<User> findAllUser() {
  7. System.out.println("*******执行查询方法*******");
  8. return null;
  9. }
  10. public int saveUser(User user) {
  11. System.out.println("*******执行添加方法********");
  12. return 0;
  13. }
  14. }

UserServProxyImpl实现类代码

  1. //代理类:完成日志输出
  2. public class UserServProxyImpl implements IUserServ {
  3. // 访问目标对象(UserServImpl)
  4. // 代理对象(UserServProxyImpl)
  5. // 创建目标对象
  6. private IUserServ iuserServ ;//= new UserServImpl();
  7. public UserServProxyImpl(IUserServ iuserServ){
  8. this.iuserServ = iuserServ;
  9. }
  10. public int deleteUserById(User user) {
  11. beforeLog();
  12. //调用目标对象里方法
  13. iuserServ.deleteUserById(user);
  14. afterLog();
  15. return 0;
  16. }
  17. public List<User> findAllUser() {
  18. beforeLog();
  19. //调用目标对象里方法
  20. iuserServ.findAllUser();
  21. afterLog();
  22. return null;
  23. }
  24. public int saveUser(User user) {
  25. beforeLog();
  26. //调用目标对象里方法
  27. iuserServ.saveUser(user);
  28. afterLog();
  29. return 0;
  30. }
  31. private void beforeLog() {
  32. System.out.println("开始执行");
  33. }
  34. private void afterLog() {
  35. System.out.println("执行完毕");
  36. }
  37. }

ActionTest测试类代码

  1. public class ActionTest {
  2. public static void main(String[] args) {
  3. //用户访问代理对象---信息->目标对象
  4. IUserServ iuserServ = new UserServProxyImpl(new UserServImpl());
  5. iuserServ.findAllUser();
  6. }
  7. }

运行结果:

开始执行
*******执行查询方法*******
执行完毕
二.动态代理实例

项目结构图:

IUserServ接口代码与UserServImpl实现类代码和上述代码相同

LogHandler类代码

  1. public class LogHandler implements InvocationHandler {
  2. //目标对象
  3. private Object targetObject;
  4. /**
  5. * 创建动态代理类
  6. * @return object(代理类)
  7. */
  8. public Object createProxy(Object targetObject){
  9. this.targetObject = targetObject;
  10. return Proxy.newProxyInstance(
  11. targetObject.getClass().getClassLoader(),
  12. targetObject.getClass().getInterfaces(), this);
  13. }
  14. @Override
  15. public Object invoke(Object proxy, Method method, Object[] args)
  16. throws Throwable {
  17. Object obj = null;
  18. try {
  19. beforeLog();
  20. //obj: 目标对象--->代理对象的返回值--->返回给调用者的信息
  21. //this.invoke("目标对象","代理对象给目标对象传递参数");
  22. //调用目标对象中方法
  23. obj = method.invoke(targetObject, args);
  24. afterLog();
  25. } catch (Exception e) {
  26. e.printStackTrace();
  27. }
  28. return obj;
  29. }
  30. //日志管理方法
  31. private void beforeLog(){
  32. System.out.println("开始执行");
  33. }
  34. private void afterLog(){
  35. System.out.println("执行完毕");
  36. }
  37. }

ActionTest测试类代码:

  1. public class ActionTest {
  2. public static void main(String[] args) {
  3. //创建代理对象iuserServ
  4. LogHandler handler = new LogHandler();
  5. IUserServ iuserServ = (IUserServ)handler.createProxy(new UserServImpl());
  6. iuserServ.deleteUserById(new User());
  7. }
  8. }

运行结果:
开始执行
******执行删除方法******
执行完毕
三.Spring AOP使用(2.x版本之前)

项目结构图:



IUserServ接口代码与UserServImpl实现类代码和上述代码相同

配置步骤:

1、配置目标对象(applicationContext.xml)

  1. <bean id="userServTarget" class="com.tarena.biz.impl.UserServImpl"/>

2、配置通知
(a)前置通知(BeforeLogAdvice)

  1. public class BeforeLogAdvice implements MethodBeforeAdvice {
  2. /**
  3. * Method method:调用目标对象的方法
  4. * Object[] args:发送给目标对象的参数列表
  5. * Object target:目标对象
  6. */
  7. public void before(Method method, Object[] args, Object target)
  8. throws Throwable {
  9. beforeLog();
  10. }
  11. private void beforeLog(){
  12. System.out.println("开始执行");
  13. }
  14. }

(b)后置通知(AfterLogAdvice)

  1. public class AfterLogAdvice implements AfterReturningAdvice {
  2. /**
  3. * Object returnValue:目标对象返回值
  4. *  Method method:目标对象方法名
  5. *  Object[] args:目标对象参数列表
  6. *  Object target:目标对象
  7. */
  8. public void afterReturning(Object returnValue, Method method,
  9. Object[] args, Object target) throws Throwable {
  10. afterLog();
  11. }
  12. private void afterLog(){
  13. System.out.println("执行完毕");
  14. }
  15. }

(c)在spring容器中,让容器管理通知(applicationContext.xml)

  1. <!-- 定义通知 -->
  2. <!-- 前置通知 -->
  3. <bean id="beforeLogAdvice" class="com.tarena.advice.BeforeLogAdvice"/>
  4. <!-- 后置通知 -->
  5. <bean id="afterLogAdvice" class="com.tarena.advice.AfterLogAdvice"/>

3、配置代理对象(applicationContext.xml)

  1. <!-- 代理类作用: 生成代理类,织入通知 -->
  2. <bean id="userServProxy"
  3. class="org.springframework.aop.framework.ProxyFactoryBean">
  4. <property name="interfaces">
  5. <!-- 可以添加多个接口 -->
  6. <list>
  7. <value>com.tarena.biz.IUserServ</value>
  8. </list>
  9. </property>
  10. <!-- 引入通知 -->
  11. <property name="interceptorNames">
  12. <list>
  13. <value>beforeLogAdvice</value>
  14. <value>afterLogAdvice</value>
  15. </list>
  16. </property>
  17. <!-- 目标对象 -->
  18. <property name="target" ref="userServTarget"/>
  19. </bean>

4.访问()
Spring容器:通过代理对象调用-->织入通知--->目标对象
程序员:访问代理对象

测试类(ActionTest):

  1. public class ActionTest {
  2. public static void main(String[] args) {
  3. ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
  4. IUserServ iuserServ = (IUserServ)ac.getBean("userServProxy");
  5. iuserServ.deleteUserById(new User());
  6. iuserServ.findAllUser();
  7. }
  8. }

运行结果:

开始执行
******执行删除方法******
执行完毕
开始执行
*******执行查询方法*******
执行完毕
四.Spring AOP使用(2.x版本之后)这种方式需要额外添加两个jar包,

存放位置在spring-framework-2.5.6.SEC01\lib\aspectj文件夹下。

项目结构图


IUserServ接口代码与UserServImpl实现类代码和上述代码相同

LogAdvice中

  1. public class LogAdvice {
  2. public void beforeLog(){
  3. System.out.println("开始执行");
  4. }
  5. public void afterLog(){
  6. System.out.println("执行完毕");
  7. }
  8. }

applicationContext.xml中

  1. <!-- spring2.x后 -->
  2. <!-- 目标对象 -->
  3. <bean id="userServImpl" class="com.tarena.biz.impl.UserServImpl"/>
  4. <!-- 通知 -->
  5. <bean id="logAdvice" class="com.tarena.advice.LogAdvice"/>
  6. <aop:config>
  7. <aop:aspect id="logAspect" ref="logAdvice">
  8. <!-- 切入点 -->
  9. <aop:pointcut id="beforePointCut"
  10. expression="execution(* saveUser*(..))"/>
  11. <aop:pointcut id="afterPointCut"
  12. expression="execution(* saveUser*(..))"/>
  13. <!-- 织入(通知作用于切入点) -->
  14. <aop:before method="beforeLog" pointcut-ref="beforePointCut"/>
  15. <aop:after method="afterLog" pointcut-ref="afterPointCut"/>
  16. </aop:aspect>
  17. </aop:config>

测试类:

  1. public class ActionTest {
  2. public static void main(String[] args) {
  3. ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
  4. IUserServ iuserServ = (IUserServ)ac.getBean("userServImpl");
  5. iuserServ.deleteUserById(new User());
  6. iuserServ.findAllUser();
  7. iuserServ.saveUser(new User());
  8. }
  9. }

运行结果
******执行删除方法******
*******执行查询方法*******
开始执行
*******执行添加方法********
执行完毕

注:如果要在业务层所有的方法前后添加日志文件,则需要更改为以下配置

  1. <aop:pointcut id="beforePointCut"
  2. expression="execution(* com.tarena.biz.*.*(..))"/>
  3. <aop:pointcut id="afterPointCut"
  4. expression="execution(* com.tarena.biz.*.*(..))"/>

运行结果:

开始执行
******执行删除方法******
执行完毕
开始执行
*******执行查询方法*******
执行完毕
开始执行
*******执行添加方法********
执行完毕

Spring AOP动态代理原理与实现方式的更多相关文章

  1. spring AOP 动态代理和静态代理以及事务

    AOP(Aspect Oriented Programming),即面向切面编程 AOP技术,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装 ...

  2. Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代理的问题

    Spring AOP底层的动态代理实现有两种方式:一种是JDK动态代理,另一种是CGLib动态代理. JDK动态代理 JDK 1.3版本以后提供了动态代理,允许开发者在运行期创建接口的代理实例,而且只 ...

  3. Spring Aop 动态代理失效分析

    1. Spring Aop 原理 Spring Aop 通过动态代理创建代理对象,在调用代理对象方法前后做增强. 2. Transactional, Async 注解失效? 当在动态代理方法中调用当前 ...

  4. spring aop 动态代理批量调用方法实例

    今天项目经理发下任务,需要测试 20 个接口,看看推送和接收数据是否正常.因为对接传输的数据是 xml 格式的字符串,所以我拿现成的数据,先生成推送过去的数据并存储到文本,以便验证数据是否正确,这时候 ...

  5. Spring AOP 动态代理 缓存

    Spring AOP应用:xml配置及注解实现. 动态代理:jdk.cglib.javassist 缓存应用:高速缓存提供程序ehcache,页面缓存,session缓存 项目地址:https://g ...

  6. Spring AOP动态代理

    出现org.springframework.aop.framework.ProxyFactoryBean cannot be cast to 错误 在类型转换的时候, 调用getObject()方法, ...

  7. Java 动态代理原理图解 (附:2种实现方式详细对比)

    ​ 动态代理在 Java 中有着广泛的应用,例如:Spring AOP 面向切面编程,Hibernate 数据查询.以及 RPC Dubbo 远程调用等,都有非常多的实际应用@mikechen 目录 ...

  8. Spring学习笔记之aop动态代理(3)

    Spring学习笔记之aop动态代理(3) 1.0 静态代理模式的缺点: 1.在该系统中有多少的dao就的写多少的proxy,麻烦 2.如果目标接口有方法的改动,则proxy也需要改动. Person ...

  9. spring源码-aop动态代理-5.3

    一.动态代理,这是一个很强大的东西哦.研发过程中我们会常用很多业务类,但是存在一个问题.如何在不修改源码逻辑的情况下,加入自己的相关逻辑.比如异常处理,日志记录等! 二.Java动态代理的两种方式JD ...

随机推荐

  1. 看think in java 随笔

    java的方法是运行期动态绑定上去的,可以根据自己真正实例化的类来判断调用哪个方法,比如子类重写了父类方法,会调用子类方法. 而利用final关键字可以让方法不能重写,就可以在编译期就绑定,这样就可以 ...

  2. 51单片机开发板(W25Q16学习)

    教程资料 链接:https://pan.baidu.com/s/142JRSPisQO2Cu6VZ2Y5YrQ 密码:eom0 今天测试开发板的W25Q16(16Mbit--Flash)写一篇文章备忘 ...

  3. C语言基础复习:字符,字符数组,字符串,字符指针

    1. 概述2. 字符2.1 字符定义和大小2.2 字符的输入和输出2.3 字符的计算3. 字符数组3.1 字符数组的定义和大小3.2 字符数组的输入和输出3.3 字符数组的计算4. 字符串4.1 字符 ...

  4. Nginx---应用场景小结

    Nginx介绍   Nginx一是一款轻量级的.高性能的HTTP.反向代理服务器,具有很高的稳定性.支持热部署.模块扩展也非常容易.Nginx采取了分阶段资源分配技术,处理静态文件和无缓存的反向代理加 ...

  5. 12.16 Daily Scrum

      Today's Task Tomorrow's Task 丁辛 实现和菜谱相关的餐厅列表. 实现和菜谱相关的餐厅列表.             邓亚梅             美化搜索框UI. 美 ...

  6. 《Linux内核设计与分析》第十七章读书笔记

    设备与模块 关于设备驱动和设备管理,四种内核成分. 设备类型:在所有Unix 系统中为了统一普通设备的操作所采用的分类. 模块: Linux 内核中用于按需加载和卸载目标码的机制. 内核对象:内核数据 ...

  7. 实训十二(stick的设定)

    上篇我们介绍到人物主角的设定,其实人物是有工具使的,那就是——stick小棍. 信息的获取.起始位置.长度的加载.边界的判断.位置.长度重置是需要我们主要考虑的问题 信息获取上考虑的使什么时候加载st ...

  8. 5-Python3从入门到实战—基础之数据类型(列表-List)

    Python从入门到实战系列--目录 列表定义 list:列表(list)是Python内置的一种数据类型,list是一种有序的集合,索引从0开始,可以进行截取.组合等: //创建列表 list1 = ...

  9. 3-Python3从入门到实战—基础之数据类型(数字-Number)

    Python从入门到实战系列--目录 Python3 中有六个标准的数据类型: Number(数字) String(字符串) List(列表) Tuple(元组) Sets(集合) Dictionar ...

  10. Maven+SSM整合.doc

    Maven + SSM整合 1开发环境搭建 1.1Eclipse4.7(Oxygen) + Tomcat8 + Maven3.5.2 2Maven Web项目创建 2.1新建maven项目 2.2 选 ...