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. python伪代码之爬取完美志愿全国历年文理分数线运行代码持续更新

    最近好多小伙伴说想搞个项目实战类的,我就花了一点时间做了一个爬虫项目(在代码复制的时候可能会有点问题,缩格一下就没有问题了) 想要获取更多源码或者答疑或者或者交流学习可以加群:725479218 # ...

  2. Elastic 技术栈之快速入门

    Elastic 技术栈之快速入门 概念 ELK 是什么 ELK 是 elastic 公司旗下三款产品 ElasticSearch .Logstash .Kibana 的首字母组合. ElasticSe ...

  3. Scala学习(五)---Scala中的类

    Scala中的类 摘要: 在本篇中,你将会学习如何用Scala实现类.如果你了解Java或C++中的类,你不会觉得这有多难,并且你会很享受Scala更加精简的表示法带来的便利.本篇的要点包括: 1. ...

  4. 【转载】固态硬盘的S.M.A.R.T详解

    文章来源于: 瑞耐斯存储技术 兵哥写这篇文章,是因为在测试的过程中看到了 SSD存在偶尔有性能下降的情况,经分析为S.M.A.R.T命令所导致,虽然这种情况看似不严重,但如果应用在诸如数据采集等关键性 ...

  5. Nginx基于TCP/UDP端口的四层负载均衡(stream模块)配置梳理

    通过我们会用Nginx的upstream做基于http/https端口的7层负载均衡,由于Nginx老版本不支持tcp协议,所以基于tcp/udp端口的四层负载均衡一般用LVS或Haproxy来做.至 ...

  6. Linux内核分析 读书笔记 (第三章)

    第三章 进程管理 3.1 进程 1.进程: 进程就是处于执行期的程序. 进程就是正在执行的程序代码的实时结果. 进程是处于执行期的程序以及相关的资源的总称. 进程包括代码段和其他资源. 2.线程:执行 ...

  7. 《Linux内核设计与实现》 第五周 读书笔记(第十八章)

    第18章 调试 20135307张嘉琪 18.1 准备开始 18.2 内核中的bug 内核中的bug多种多样,它们的产生可以有无数的原因,同时它们的表象也变化多端,从明白无误的错误代码(比如,没有把正 ...

  8. /var/lib/mysql 的访问权限问题 Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)

    mysql 登录不进去 提示Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2) she ...

  9. Alpha冲刺之事后诸葛亮

    组长博客 作业博客 项目Postmortem 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们的软件针对的是福大学子来到食堂会犹豫不决无法决定吃什么 ...

  10. Balanced Ternary String CodeForces - 1102D (贪心+思维)

    You are given a string ss consisting of exactly nn characters, and each character is either '0', '1' ...