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();

相关文章
|
12天前
|
安全 Java 编译器
JDK 10中的局部变量类型推断:Java编程的简化与革新
JDK 10引入的局部变量类型推断通过`var`关键字简化了代码编写,提高了可读性。编译器根据初始化表达式自动推断变量类型,减少了冗长的类型声明。虽然带来了诸多优点,但也有一些限制,如只能用于局部变量声明,并需立即初始化。这一特性使Java更接近动态类型语言,增强了灵活性和易用性。
95 53
|
5天前
|
IDE Java 编译器
开发 Java 程序一定要安装 JDK 吗
开发Java程序通常需要安装JDK(Java Development Kit),因为它包含了编译、运行和调试Java程序所需的各种工具和环境。不过,某些集成开发环境(IDE)可能内置了JDK,或可使用在线Java编辑器,无需单独安装。
|
25天前
|
设计模式 Java API
[Java]静态代理与动态代理(基于JDK1.8)
本文介绍了代理模式及其分类,包括静态代理和动态代理。静态代理分为面向接口和面向继承两种形式,分别通过手动创建代理类实现;动态代理则利用反射技术,在运行时动态创建代理对象,分为JDK动态代理和Cglib动态代理。文中通过具体代码示例详细讲解了各种代理模式的实现方式和应用场景。
23 0
[Java]静态代理与动态代理(基于JDK1.8)
|
1月前
|
Java
【编程进阶知识】静态代理、JDK动态代理及Cglib动态代理各自存在的缺点及代码示例
本文介绍了三种Java代理模式:静态代理、JDK动态代理和Cglib动态代理。静态代理针对特定接口或对象,需手动编码实现;JDK动态代理通过反射机制实现,适用于所有接口;Cglib动态代理则基于字节码技术,无需接口支持,但需引入外部库。每种方法各有优缺点,选择时应根据具体需求考虑。
21 1
|
1月前
|
Java
让星星⭐月亮告诉你,jdk1.8 Java函数式编程示例:Lambda函数/方法引用/4种内建函数式接口(功能性-/消费型/供给型/断言型)
本示例展示了Java中函数式接口的使用,包括自定义和内置的函数式接口。通过方法引用,实现对字符串操作如转换大写、数值转换等,并演示了Function、Consumer、Supplier及Predicate四种主要内置函数式接口的应用。
25 1
|
1月前
|
Java
Java基础之 JDK8 HashMap 源码分析(中间写出与JDK7的区别)
这篇文章详细分析了Java中HashMap的源码,包括JDK8与JDK7的区别、构造函数、put和get方法的实现,以及位运算法的应用,并讨论了JDK8中的优化,如链表转红黑树的阈值和扩容机制。
25 1
|
1月前
|
Java
深入理解Java动态代理
深入理解Java动态代理
19 1
|
29天前
|
Java
Java代码解释静态代理和动态代理的区别
### 静态代理与动态代理简介 **静态代理**:代理类在编译时已确定,目标对象和代理对象都实现同一接口。代理类包含对目标对象的引用,并在调用方法时添加额外操作。 **动态代理**:利用Java反射机制在运行时生成代理类,更加灵活。通过`Proxy`类和`InvocationHandler`接口实现,无需提前知道接口的具体实现细节。 示例代码展示了两种代理方式的实现,静态代理需要手动创建代理对象,而动态代理通过反射机制自动创建。
|
1月前
|
设计模式 缓存 Java
从源码学习Java动态代理|8月更文挑战
从源码学习Java动态代理|8月更文挑战
|
5月前
|
设计模式 Java 程序员
java动态代理(JDK和cglib)
java动态代理(JDK和cglib)
31 0
下一篇
无影云桌面