大家都知道AOP使用了代理模式,本文主要介绍两个代理模式怎么设置以及区别,对原文一些内容进行了引用后加入了自己的理解和更深入的阐述:
 
一、JDK代理和CGLIB代理的底层实现区别
* JDK代理只能针对实现了接口的类以反射的方式生成代理,而不能针对类 ,所以也叫“接口代理”
* CGLIB是针对类实现代理的,主要对指定的类以字节码转换的方式(ASM框架)生成一个子类,并重写其中的方法。
   因为是创建目标类的子类,所以目标类必须要有无参构造函数(子类的有参构造函数会调用父类无参),否则报错
【注意】:  有两种特殊情况,static与final方法:
    

 

Final方法

Static方法

Jdk代理

接口无法使用final关键字,所以不能用。

【报错】

接口方法使用了static后代理对象将无法访问此方法,所以不能用。

【报错】

Cglib代理

父类方法使用了final之后,子类将无法对其进行重写,无法拦截。

【不报错,但不拦截】

父类方法使用了static之后,子类将无法对其进行重写,无法拦截。

【不报错,但不拦截】

同时,当使用cglib代理的时候,目标类一定不能为final类(不能被继承),否则报错。  
 
以上可以看出使用代理的时候,尽量不要使用final和static关键字。
  
 
二、Spring中两个模式的调配:
1、如果目标对象实现了接口,默认会采用JDK的动态代理机制实现AOP,但是可以强制使用CGLIB实现AOP ;
    缺点:必须实现接口,并且生成的代理对象也只能声明成为其中一个接口,其他接口的方法和自己的方法访问不到。
2、如果目标对象没有实现接口,必须使用CGLIB生成代理,spring会自动在CGLIB和JDK动态代理之间切换 。

3.如何强制使用CGLIB生成代理? 
* 添加CGLIB库,<SPRING_HOME>/lib/cglib/*.jar (其实Spring的核心包包括了cglib-nodep-2.2.jar,或者用MyEclipse构建项目也会自动引入)

* 在spring的配置文件的约束中(beans的属性)加入xmlns:aop的相关信息后,再于bean空间中加入: 
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
 
下面是我的applicationContext.xml的前面一部分,以供参考:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop = "http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd "
> <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
...

三、注意事项

当使用jdk代理的时候,经常会发生一个错误:

java.lang.ClassCastException: com.sun.proxy.$Proxy7 cannot be cast to XXXXX

解析:明显这是jdk代理对象转换的错误,而从上面可以知道jdk代理是根据目标类的接口生成一个继承这些接口的类对象,当使用容器调出对象的时候就是代理对象与目标对象同级,所以二者之间不能强制转换,声明类应该为他们俩共有的接口类,如果声明成目标类,则会报出以上的错误。

ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");        
Dao dao = (Dao) ac.getBean("dao"); // 报错

解决:方法1、将声明类改为目标对象的接口。  IDao dao = (IDao) ac.getBean("dao");

   方法2、cglib代理生成的是一个子类,可以用父类进行声明,也不会报错,所以强制使用cglib代理也可以解决。【强制方式上面已经给出】

 

spring的AOP动态代理--JDK代理和CGLIB代理区分以及注意事项的更多相关文章

  1. 总结两种动态代理jdk代理和cglib代理

    动态代理 上篇文章讲了什么是代理模式,为什么用代理模式,从静态代理过渡到动态代理. 这里再简单总结一下 什么是代理模式,给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原 ...

  2. Java中jdk代理和cglib代理

    代理模式 给某一个对象提供一个代理,并由代理对象控制对原对象的引用.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 在Java中代理模式从实 ...

  3. jdk代理和cglib代理

    1.jdk静态代理(静态代理和动态代理) 本质:在内存中构建出接口的实现类. 缺陷:只能对实现接口的类实现动态代理, 使用cglib可以对没有实现接口的类进行动态代理. 2.cglib动态代理     ...

  4. jdk代理和cglib代理源代码之我见

    以前值是读过一遍jdk和cglib的代理,时间长了,都忘记入口在哪里了,值是记得其中的一些重点了,今天写一篇博客,当作是笔记.和以前一样,关键代码,我会用红色标记出来. 首先,先列出我的jdk代理对象 ...

  5. Spring中AOP的两种代理方式(Java动态代理和CGLIB代理)

    第一种代理即Java的动态代理方式上一篇已经分析,在这里不再介绍,现在我们先来了解下GCLIB代理是什么?它又是怎样实现的?和Java动态代理有什么区别? cglib(Code Generation ...

  6. 设计模式---JDK动态代理和CGLIB代理

    Cglig代理设计模式 /*测试类*/ package cglibProxy; import org.junit.Test; public class TestCglib { @Test public ...

  7. JDK动态代理和 CGLIB 代理

    JDK动态代理和 CGLIB 代理 JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期期间创建一个接口的实现类来完成对目标对象的代理. 代码示例 接口 public interface ...

  8. SpringAOP-JDK 动态代理和 CGLIB 代理

    在 Spring 中 AOP 代理使用 JDK 动态代理和 CGLIB 代理来实现,默认如果目标对象是接口,则使用 JDK 动态代理,否则使用 CGLIB 来生成代理类. 1.JDK 动态代理 那么接 ...

  9. 静态代理、动态代理和cglib代理

    转:https://www.cnblogs.com/cenyu/p/6289209.html 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处 ...

随机推荐

  1. 穿透Session 0 隔离(一)

    服务(Service)对于大家来说一定不会陌生,它是Windows 操作系统重要的组成部分.我们可以把服务想像成一种特殊的应用程序,它随系统的“开启-关闭”而“开始-停止”其工作内容,在这期间无需任何 ...

  2. elasticsearch数据迁移——elasticsearch-dump使用

    先安装好nodejs和nodejs的包管理工具npm.然后安装elasticsearch-dump: npm install elasticdump 下面迁移数据: 先在目的地址创建一个index来储 ...

  3. Linux内核设计与实现——内核同步

    内核同步 同步介绍 同步的概念 临界区:也称为临界段,就是訪问和操作共享数据的代码段. 竞争条件: 2个或2个以上线程在临界区里同一时候运行的时候,就构成了竞争条件. 所谓同步.事实上防止在临界区中形 ...

  4. Python HTML Resolution Demo - SGMLParser & PyQuery

    1. SGMLParser: 这里定义了一个Parse类,继承SGMLParser里面的方法.使用一个变量is_h4做标记判定html文件中的h4标签,如果遇到h4标签,则将标签内的内容加入到Pars ...

  5. Python+Django+Bootstrap 框架环境搭建

    1.安装python和pip(python.pip安装自行百度,pip是一个安装和管理 Python 包的工具) 2.配置python环境变量(python和scripts目录都需要配置) 3.安装D ...

  6. Django框架之模板语法(重要!)

    一.什么是模板? 只要是在html里面有模板语法就不是html文件了,这样的文件就叫做模板. 二.模板语法分类 1.模板语法之变量:语法为 {{ }}: 在 Django 模板中遍历复杂数据结构的关键 ...

  7. java栈的实现

    可以采用数组与链表两种方法来实现栈. 1.用数组实现栈 import java.util.Arrays; public class MyStack<E>{ private Object[] ...

  8. LeetCode:二叉树的后序遍历【145】

    LeetCode:二叉树的后序遍历[145] 题目描述 给定一个二叉树,返回它的 后序 遍历. 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [3,2,1] 进阶: 递归算法很 ...

  9. tomcat 启动报错(tomcat org.apache.catalina.core.StandardContext startInternal)

    转载:https://blog.csdn.net/chenlong316048157/article/details/18698611 org.apache.catalina.core.Standar ...

  10. fetch 添加请求头headers

    // var headers = new Headers(); // headers.append('Authorization', localStorage.getItem('token')); f ...