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. Identity(三)

    本文摘自木宛城主的 ASP.NET MVC 随想录——开始使用ASP.NET Identity,初级篇 - 木宛城主 - 博客园 由于ASP.NET Membership.ASP.NET Simple ...

  2. CF1097F Alex and a TV Show 莫比乌斯反演、bitset

    传送门 发现自己对mobius反演的理解比较浅显-- 首先我们只需要维护每一个数的出现次数\(\mod 2\)的值,那么实际上我们只需要使用\(bitset\)进行维护,每一次加入一个数将其对应次数异 ...

  3. java 基础01

    标识符:字母,下划线和美元符号,数字组成大小写敏感,无长度限制 关键字: 数据类型

  4. Flask系列学习

    一.Flask系列学习(基础) Flask学习-前言 Flask学习-Flask基础之WSGI Flask学习-Flask app启动过程 Flask学习-Flask app接受第一个HTTP请求 F ...

  5. C#大型电商项目优化(二)——嫌弃EF与抛弃EF

    上一篇博文中讲述了使用EF开发电商项目的代码基础篇,提到EF后,一语激起千层浪.不少园友纷纷表示:EF不适合增长速度飞快的互联网项目,EF只适合企业级应用等等. 也有部分高手提到了分布式,确实,性能优 ...

  6. 用JS制作一个信息管理平台(1)

    首先,介绍一些需要用到的基本知识. [JSON] JSON是数据交互中,最常用的一种数据格式. 由于各种语言的语法都不相同,在传递数据时,可以将自己语言中的数组.对象等转换为JSON字符串. 传递之后 ...

  7. width,height为多少px时,A4纸打印时刚好一页?

    计算方式一般的分辨率为XX像素/英寸,其中一英寸为25.4毫米.所以一毫米的像素数就为XX/25.4.现在的工作就是求XX的值了,把XX的值求出来以后,直接用XX/25.4 * 210就得到A4纸的像 ...

  8. 求去掉一条边使最小割变小 HAOI2017 新型城市化

    先求最小割,然后对残量网络跑Tarjan.对于所有满流的边,若其两端点不在同一个SCC中,则这条边是满足条件的. 证明见 来源:HAOI2017 新型城市化

  9. required: true,el-upload :action="UploadUrl()"

    <el-form-item label="所属班级:" prop="Name" :rules="[{ required: true, messa ...

  10. 12.10 Daily Scrum

    各种大作业,进度会放缓一些.   Today's Task Tomorrow's Task 丁辛 完善餐厅列表,显示距离. 实现和菜谱相关的餐厅列表.             邓亚梅          ...