说起Spring的AOP(Aspect-Oriented Programming)面向切面编程大家都很熟悉(Spring不是这次博文的重点),但是我先提出几个问题,看看同学们是否了解,如果了解的话可以不用继续往下读:

  1. Spring的AOP的实现方式有哪些?

  2. 为什么使用代理机制?

  3. 它们是怎么实现的?

  4. 它们的区别是什么?

  下面进入正题,Spring采用代理的方式实现AOP,具体采用了JDK的动态代理和CGLib实现。使用动态代理和CGLib的目的是在现有类的基础上增加一些功能。简单地将就是有一个Proxy类,实现了原始类的方法,并且在原始类的基础上增加了新的功能。那么这么做可以实现很多功能:

  1. 在方法前后进行日志处理。

  2. 进行额外的校验,比如参数的验证功能等。

  3. 实现一些懒加载,也就是实例化的时候如果不去调用真正的方法的时候,这个类的属性就不会存在(Hibernate有这样类似的功能)。

  下面咱们用简单的代码实现它是如何进行代理的,首先采用的是JDK的动态代理实现:

  定义一个接口:

package com.hqs.proxy;/*** 操作系统光接口* @author hqs**/
public interface OpSystem {public void work();
}

  定义一个实现类:

package com.hqs.proxy;/*** Mac 的实现* @author hqs**/
public class Mac implements OpSystem {public void work() {System.out.println("Mac is running");    }}

  关键位置来了,我们通过实现JDK自带的反射机制的包的InvocationHandler来进行反射处理,实现它之后需要实现里边的invoke方法,这个invoke方法里边的参数分别为:代理类实例,用于调用method的;method参数是实际执行的方法;args所传输的参数数组。

package com.hqs.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class OpHandler implements InvocationHandler {private final OpSystem ops; public OpHandler(OpSystem ops) {this.ops = ops;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Before system running");method.invoke(ops, args);System.out.println("After system running");return null;}public static void main(String[] args) {Mac mac = new Mac();OpHandler oph = new OpHandler(mac);OpSystem os = (OpSystem)Proxy.newProxyInstance(oph.getClass().getClassLoader(),mac.getClass().getInterfaces(), oph);os.work();System.out.println(os.getClass());}}输出:
Before system running
Mac is running
After system running
class com.sun.proxy.$Proxy0

  然后看到里边的main方法中,代理类实例化对象的方法Proxy.newProxyInstance,这个是JDK的反射方法去实例化代理类,其中有三个参数分别是,去实例化代理类的class loader;所代理的类的所有接口Class数组;hander处理类,用于做拦截使用的类。最后我输出了一下os.getClass(),大家可以看到的是代理类的实例,而不是真正代理类的实例,这么做的好处就是很方便的复用这个代理类,比如你可以重复调用它而不用去重新实例化新类,再一点就是你可以针对不同的方法进行拦截,比如你可以method.getName()去判断调用的方法名字是什么从而更细粒度的拦截方法。咱们继续看用CGLib的实现:  

package com.hqs.proxy;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;/*** CGLib Interceptor用于方法拦截* @author hqs**/
public class CGLibInterceptor implements MethodInterceptor {private final Mac mac;public CGLibInterceptor(Mac mac) {this.mac = mac;}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {System.out.println("Before system running");method.invoke(mac, args);System.out.println("After system running");return null;}public static void main(String[] args) {Mac mac = new Mac(); //实例而非接口MethodInterceptor handler = new CGLibInterceptor(mac);Mac m = (Mac)Enhancer.create(mac.getClass(), handler);m.work();System.out.println(m.getClass());}}输出:
Before system running
Mac is running
After system running
class com.hqs.proxy.Mac$$EnhancerByCGLIB$$1f2c9d4a

  首先需要引入cglib包,然后才能使用他的MethodInterptor,它也采用method.invoke实现对代理类的调用。它的代理类创建采用Enhancer的create方法,其中传入了需要创建的类的class,以及Callback对象,因为MethodInterceptor继承了Callback对象。用于指向方法前后进行调用的类。  

public interface MethodInterceptor
extends Callback

  这是这两个类的基本实现,那么它们的区别是什么呢?

  1. JDK的动态代理只能针对接口和其实现类,如果没有实现类只有接口也是可以代理的,这里就不在举例了。为什么JDK的动态代理只针对接口代理,因为这个是JDK的定义。
  2. 如果不针对接口实现动态代理那就用到了CGLib了,也就是可以针对具体的类进行代理,大家可以参考我的代码。

  这些是它们的根本区别,但是Spring推荐使用JDK的动态代理,面向接口去编程。使用CGLib去做代理的时候需要注意,它生成的代理类存放在JVM的Perm space里边,那么是不是生成的代理对象就不进行回收了?其实不是的,不经常回收但是还是回收的,当类被加载,加载类的classLoader什么时候变得对垃圾回收可用的时候才进行回收。也就是你自己创建所有类移除classLoader之后,那么这个classLoader就会被回收,一般非常精通CGLib的话可以进行这块内容深入开发,因为它可以做出amzing的事情如果你熟悉的话。

  如果有不对的地方欢迎拍砖~

  

  

转载于:https://www.cnblogs.com/huangqingshi/p/7651376.html

浅谈Spring的AOP实现-代理机制相关推荐

  1. 浅谈Spring中JDK动态代理与CGLIB动态代理

    前言 Spring是Java程序员基本不可能绕开的一个框架,它的核心思想是IOC(控制反转)和AOP(面向切面编程).在Spring中这两个核心思想都是基于设计模式实现的,IOC思想的实现基于工厂模式 ...

  2. 浅谈Spring框架AOP概念

    何为AOP? AOP(Aspect Oriented Programming,面向切面编程):AOP是一种新的方法论,在这之前相信我们都听过面向对象编程(OOP),AOP就是对OOP的补充,它们的关系 ...

  3. 浅谈spring之jdk动态代理

    学习来源于b站动力节点 JDK动态代理 ​ 动态代理的实现方式常用的有两种:使用JDK的Proxy,与通过CGLIB生成代理.jdk的动态要求目标对象必须实现接口,这是java设计上的要求,使用jdk ...

  4. 浅谈 Spring IOC和AOP

    浅谈 Spring IOC和AOP IOC 控制反转 以前创建对象的主动权和时机是由于自己把握的,现在将这种权利转移到Spring容器中,并且根据配置文件去创建对象管理对象 ioc的注入方式有三种:构 ...

  5. spring中AOP动态代理的两种方式

    AOP动态代理的两种方式 Spring AOP动态代理的方式(spring的AOP默认是JDK Proxy) 浅谈这两种动态代理 JDK的动态代理,需要有实现接口 动态代理--JDK Proxy ⚫ ...

  6. 由openSession、getCurrentSession和HibernateDaoSupport浅谈Spring对事物的支持

    由openSession.getCurrentSession和HibernateDaoSupport浅谈Spring对事物的支持 Spring和Hibernate的集成的一个要点就是对事务的支持,op ...

  7. 浅谈Spring IOC的理解

    浅谈Spring IOC的理解 学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊 ...

  8. 浅谈:Spring Boot原理分析,切换内置web服务器,SpringBoot监听项目(使用springboot-admin),将springboot的项目打成war包

    浅谈:Spring Boot原理分析(更多细节解释在代码注释中) 通过@EnableAutoConfiguration注解加载Springboot内置的自动初始化类(加载什么类是配置在spring.f ...

  9. 浅谈Spring IOC和DI及Spring工厂类

    浅谈Spring IOC和DI及Spring的工厂类 文章目录 浅谈Spring IOC和DI及Spring的工厂类 一. IOC 1.什么是IOC 2.为什么使用IOC 传统开发模式的弊端 3. 使 ...

最新文章

  1. mysql半主从_转mysql半主从同步
  2. 如何制定一个高效的数据保护计划
  3. 魔兽世界高法伤技能列表
  4. SpringBoot中配置为开发模式,代码修改后不用重新运行
  5. 机器学习sklearn19.0聚类算法——Kmeans算法
  6. freemarker配置
  7. Unity 2D游戏开发教程之2D游戏的运行效果
  8. 字符串之从规定的字符串中根据下标得到字符
  9. 是否显示展开_Creo7.0教程之绝对精度对钣金件展开的作用详解
  10. redux 函数式组件_如何从函数式编程的角度学习Redux
  11. linux awk
  12. class meta
  13. 搜狗浏览器广告拦截插件_拦截烦人的网页广告,增加上网体验
  14. bc显示小数点前的0
  15. C/S与B/S系统测试的不同点和相同点
  16. Cesium教程系列汇总
  17. git revert与git reset
  18. 网络运维系列:Ubnt ER-X初始化和开启硬件NAT
  19. 在 Cocos Creator 中使用缓动系统(cc.tween)
  20. PCIE数据采集软件使用

热门文章

  1. html插入flash代码_初学者必备Web开发APP,支持代码补全,一键插入代码,厉害了!...
  2. Vue项目中使用Echarts(二)
  3. LeetCode 1806. 还原排列的最少操作步数(模拟)
  4. 天池 在线编程 聪明的销售(计数+贪心)
  5. LeetCode 79. 单词搜索(回溯DFS)
  6. python format 冒号_python之格式化输出
  7. 什么是spring_Spring 源码第三弹!EntityResolver 是个什么鬼?
  8. 机器学习算法优缺点对比及选择
  9. mysql一图秒懂秒清晰 - join连接 ,left join左连接 ,right join右连接 ,inner join内连接
  10. 直击行业痛点!端侧模型部署的成熟解决方案有了!