java动态代理(JDK和cglib)

简介: java动态代理(JDK和cglib)

JAVA的动态代理
代理模式
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
按照代理的创建时期,代理类可以分为两种。
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。

首先看一下静态代理:
1、Count.java
package net.battier.dao;

/**

  • 定义一个账户接口
  • @author Administrator
    */
    public interface Count {
    // 查看账户方法
    public void queryCount();
    // 修改账户方法
    public void updateCount();
    }
    2、CountImpl.java
    package net.battier.dao.impl;
    import net.battier.dao.Count;
  • 委托类(包含业务逻辑)
    public class CountImpl implements Count {
    @Override
    public void queryCount() {

     System.out.println("查看账户方法...");  
    

    }
    public void updateCount() {

     System.out.println("修改账户方法...");  
    

    、CountProxy.java
    //代码效果参考:http://www.zidongmutanji.com/bxxx/146312.html

  • 这是一个代理类(增强CountImpl实现类)
    public class CountProxy implements Count {
    private CountImpl countImpl;
    /**

    • 覆盖默认构造器
    • @param countImpl
      /
      public CountProxy(CountImpl countImpl) {
      this.countImpl = countImpl;
      System.out.println("事务处理之前");
      // 调用委托类的方法;
      countImpl.queryCount();
      System.out.println("事务处理之后");
      countImpl.updateCount();
      3、TestCount.java
      package net.battier.test;
      import net.battier.dao.impl.CountImpl;
      import net.battier.dao.impl.CountProxy;
      测试Count类
      public class TestCount {
      public static void main(String[] args) {
      CountImpl countImpl = new CountImpl();
      CountProxy countProxy = new CountProxy(countImpl);
      countProxy.updateCount();
      countProxy.queryCount();
      观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。
      再来看一下动态代理:
      JDK动态代理中包含一个类和一个接口:
      InvocationHandler接口:
      public interface InvocationHandler {
      public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
      }
      参数说明:
      Object proxy:指被代理的对象。
      Method method:要调用的方法
      Object[] args:方法调用时所需要的参数
      可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。
      //代码效果参考:http://www.zidongmutanji.com/zsjx/416403.html

Proxy类:
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子类实例
Ps:类加载器
在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器;
Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的;
Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类;
AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。
动态代理
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
动态代理示例:
1、BookFacade.java
public interface BookFacade {
public void addBook();
2、BookFacadeImpl.java
import net.battier.dao.BookFacade;
public class BookFacadeImpl implements BookFacade {
public void addBook() {
System.out.println("增加图书方法。。。");
、BookFacadeProxy.java
package net.battier.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

  • JDK动态代理代理类
  • @author student
    public class BookFacadeProxy implements InvocationHandler {
    private Object target;
    • 绑定委托对象并返回一个代理类
    • @param target
    • @return
      public Object bind(Object target) {
      this.target = target;
      //取得代理对象
      return Proxy.newProxyInstance(target.getClass().getClassLoader(),
           target.getClass().getInterfaces(), this);   //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)  
      
    • 调用方法
      public Object invoke(Object proxy, Method method, Object[] args)
       throws Throwable {  
      
      Object result=null;
      System.out.println("事物开始");
      //执行方法
      result=method.invoke(target, args);
      System.out.println("事物结束");
      return result;
      3、TestProxy.java
      import net.battier.dao.impl.BookFacadeImpl;
      import net.battier.proxy.BookFacadeProxy;
      public class TestProxy {
      BookFacadeProxy proxy = new BookFacadeProxy();
      BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());
      bookProxy.addBook();

//代码效果参考:http://www.zidongmutanji.com/zsjx/364725.html
但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。
Cglib动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
示例
1、BookFacadeCglib.java
2、BookCadeImpl1.java

  • 这个是没有实现接口的实现类
    public class BookFacadeImpl1 {
     System.out.println("增加图书的普通方法...");  
    
    3、BookFacadeProxy.java
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
  • 使用cglib动态代理
    public class BookFacadeCglib implements MethodInterceptor {

    • 创建代理对象
      public Object getInstance(Object target) {
      Enhancer enhancer = new Enhancer();
      enhancer.setSuperclass(this.target.getClass());
      // 回调方法
      enhancer.setCallback(this);
      // 创建代理对象
      return enhancer.create();
      // 回调方法
      public Object intercept(Object obj, Method method, Object[] args,

       MethodProxy proxy) throws Throwable {  
      

      proxy.invokeSuper(obj, args);
      return null;
      4、TestCglib.java
      import net.battier.dao.impl.BookFacadeImpl1;
      import net.battier.proxy.BookFacadeCglib;
      public class TestCglib {

      BookFacadeCglib cglib=new BookFacadeCglib();
      BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());
      bookCglib.addBook();

相关文章
|
1月前
|
安全 Java 编译器
JDK 10中的局部变量类型推断:Java编程的简化与革新
JDK 10引入的局部变量类型推断通过`var`关键字简化了代码编写,提高了可读性。编译器根据初始化表达式自动推断变量类型,减少了冗长的类型声明。虽然带来了诸多优点,但也有一些限制,如只能用于局部变量声明,并需立即初始化。这一特性使Java更接近动态类型语言,增强了灵活性和易用性。
106 53
|
1月前
|
安全 Java 开发者
AOP中的JDK动态代理与CGLIB动态代理:深度解析与实战模拟
【11月更文挑战第21天】面向切面编程(AOP,Aspect-Oriented Programming)是一种编程范式,它通过将横切关注点(cross-cutting concerns)与业务逻辑分离,以提高代码的可维护性和可重用性。在Java开发中,AOP的实现离不开动态代理技术,其中JDK动态代理和CGLIB动态代理是两种常用的方式。本文将从背景、历史、功能点、业务场景、底层逻辑等多个维度,深度解析这两种代理方式的区别,并通过Java示例进行模拟和比较。
45 4
|
1月前
|
Java
JAVA 静态代理 & 动态代理
【11月更文挑战第14天】静态代理是一种简单的代理模式实现,其中代理类和被代理类的关系在编译时已确定。代理类实现与被代理类相同的接口,并持有被代理类的实例,通过调用其方法实现功能增强。优点包括代码结构清晰,易于理解和实现;缺点是对于多个被代理类,需为每个类编写相应的代理类,导致代码量大增,维护成本高。动态代理则在运行时动态生成代理类,更加灵活,减少了代码冗余,但可能引入性能损耗和兼容性问题。
|
2月前
|
设计模式 Java API
[Java]静态代理与动态代理(基于JDK1.8)
本文介绍了代理模式及其分类,包括静态代理和动态代理。静态代理分为面向接口和面向继承两种形式,分别通过手动创建代理类实现;动态代理则利用反射技术,在运行时动态创建代理对象,分为JDK动态代理和Cglib动态代理。文中通过具体代码示例详细讲解了各种代理模式的实现方式和应用场景。
33 0
[Java]静态代理与动态代理(基于JDK1.8)
|
2月前
|
Java
【编程进阶知识】静态代理、JDK动态代理及Cglib动态代理各自存在的缺点及代码示例
本文介绍了三种Java代理模式:静态代理、JDK动态代理和Cglib动态代理。静态代理针对特定接口或对象,需手动编码实现;JDK动态代理通过反射机制实现,适用于所有接口;Cglib动态代理则基于字节码技术,无需接口支持,但需引入外部库。每种方法各有优缺点,选择时应根据具体需求考虑。
23 1
|
2月前
|
Java
让星星⭐月亮告诉你,jdk1.8 Java函数式编程示例:Lambda函数/方法引用/4种内建函数式接口(功能性-/消费型/供给型/断言型)
本示例展示了Java中函数式接口的使用,包括自定义和内置的函数式接口。通过方法引用,实现对字符串操作如转换大写、数值转换等,并演示了Function、Consumer、Supplier及Predicate四种主要内置函数式接口的应用。
30 1
|
2月前
|
Java
Java代码解释静态代理和动态代理的区别
### 静态代理与动态代理简介 **静态代理**:代理类在编译时已确定,目标对象和代理对象都实现同一接口。代理类包含对目标对象的引用,并在调用方法时添加额外操作。 **动态代理**:利用Java反射机制在运行时生成代理类,更加灵活。通过`Proxy`类和`InvocationHandler`接口实现,无需提前知道接口的具体实现细节。 示例代码展示了两种代理方式的实现,静态代理需要手动创建代理对象,而动态代理通过反射机制自动创建。
|
6月前
|
设计模式 Java 程序员
java动态代理(JDK和cglib)
java动态代理(JDK和cglib)
41 0
|
设计模式 Java 数据安全/隐私保护
剖析代理模式及Java两种动态代理(JDK动态代理和CGLIB动态代理)
本文详述了代理模式以及我们经常接触到的两种具体实现(JDK动态代理和CGLIB动态代理),为读者理解代理模式、JDK动态代理和CGLIB动态代理提供帮助
203 0
剖析代理模式及Java两种动态代理(JDK动态代理和CGLIB动态代理)
|
设计模式 Java 数据库连接
Java 动态代理机制 (一) JDK Proxy详解
JDK Proxy 代理是可以根据我们的 接口 Interface 生成类的字节码,从而可以在 Java 中为所欲为的一种技术,包括对象增强(修改成员变量),函数增强(在函数前后执行别的代码),根据接口名执行不同逻辑 等。在 Mybatis 中有典型应用。它的本质是 由 Proxy 生成一个 代理对象,实现我们的接口。这个对象中有我们的回调函数。当调用 代理对象的接口方法时,这个对象再调用我们的回调函数,我们的回调函数再调用原对象的对应方法。从而实现代理。为了实现代理模式,Proxy 用了另外一种设计模式:命令模式。 不过,如果我们没有接口,直接是个类,那么 Proxy 将不能用,我们可能需
下一篇
DataWorks