动态代理和静态代理

代理模式角色如下:
在这里插入图片描述

  1. Subject(抽象主题):代理类和真实主题的共用的接口,提供对外的公共方法;
  2. RealSubject(真实主题):真正实现业务逻辑的类;
  3. Proxy(代理主题):用来代理和封装真实主题;要与被真实主题实现相同的抽象主题;

代理模式结构图:
在这里插入图片描述

代理分为静态代理和动态代理

静态代理:
a. 静态代理实现简单,且不侵入原代码,在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。
b. 当被代理类需要增加、删除、修改方法的时候,代理类都要同时修改,不易维护。
c. 当需要代理多个类的时候,就需要创建多个代理类,造成代理类过多不易维护。 如果只用一个代理类,势必要实现多个接口,会造成类过于庞大,也不易维护
动态代理:
JDK动态代理
a. 是利用反射机制生成一个实现代理接口的匿名类。
b. 主要是针对接口,要求目标对象必须实现接口,不能针对类。
c. JDK动态代理在运行时动态生成的,编译完成后没有实际的class文件,而是在运 行时在JVM中动态生成类字节码
CGLIB动态代理:
a. 底层采用ASM字节码生成框架,使用字节码技术生成代理类比反射效率高。
b. CGLib动态代理在运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。
c. 针对类,无需实现接口,对指定的类生成一个子类,覆盖其中的方法,达到代理类无侵入。
d. CGLib动态代理是动态生成被代理类的子类,所以被final修饰的方法不能进行CGLib代理。

代码实现

静态代理代码实现:
编写一个接口 UserService 也就是Subject(抽象主题)以及该接口实现类 UserServiceImpl也就是RealSubject(真实主题)

/**
 * 接口
 */
public interface UserService {
    //汇报
    public void report();
}


/**
 * 实现类
 */
public class UserServiceImpl implements UserService {
    //汇报
    public void report() {
        System.out.println("汇报异常.....");
    }
}

编写静态代理类,也就是Proxy(代理主题)

/**
 * 静态代理类
 * 1. 代理类与被代理类要有相同的接口
 * 2. 代理类需要在被代理方法执行之前或之后执行一些方法
 */
public class StaticProxy implements UserService {
    private UserService target;

    public StaticProxy(UserService target) {
        this.target = target;
    }

    public void report() {
        this.before();
        target.report();
        this.after();
    }


    // 调用方法之前执行
    private void before() {
        System.out.println("发现异常......");
    }

    // 调用方法之后执行
    private void after() {
        System.out.println("处理异常.......");
    }
}

代码执行

  /**
     * 代理模式角色:
     * Subject(抽象主题):代理类和真实主题的公共对外方法,也是代理类代理真实主题相同的接口;
     * RealSubject(真实主题):真正实现业务逻辑的类;
     * Proxy(代理主题):用来代理和封装真实主题;要与被代理类实现相同的接口Subject
     */
    public static void main(String[] args) {
        /**
         * 静态代理的优缺点:
         *  优点:静态代理实现简单,且不侵入原代码,在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。
         *  缺点:
         *       1. 当被代理类需要增加、删除、修改方法的时候,代理类都要同时修改,不易维护。
         *       2. 当需要代理多个类的时候,就需要创建多个代理类,造成代理类过多不易维护。
         *          如果只用一个代理类,势必要实现多个接口,会造成类过于庞大,也不易维护
         */
        //静态代理方法测试
        UserService userService = new UserServiceImpl();
        StaticProxy proxy = new StaticProxy(userService);
        proxy.report();
    }

运行结果
在这里插入图片描述

JDK动态代理代码实现:
编写一个接口 UserService 也就是Subject(抽象主题)以及该接口实现类 UserServiceImpl也就是RealSubject(真实主题)

/**
 * 接口
 */
public interface UserService {
    //汇报
    public void report();
}


/**
 * 实现类
 */
public class UserServiceImpl implements UserService {
    //汇报
    public void report() {
        System.out.println("汇报异常.....");
    }
}

编写JDK动态代理类,也就是Proxy(代理主题)


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * jdk动态代理 是利用反射机制生成一个实现代理接口的匿名类。
 *  1. jdk动态代理主要是针对接口,要求目标对象必须实现接口,不能针对类。
 *  2. 动态代理是在运行时动态生成的,编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中
 */
public class JdkProxy {
    private Object target;// 维护一个目标对象

    public JdkProxy(Object target) {
        this.target = target;
    }

    // 为目标对象生成代理对象
    public Object getProxyInstance() {
        /**
         *  Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
         *  参数说明:
         *      ClassLoader loader        //指定当前目标对象使用类加载器
         *      Class<?>[] interfaces    //目标对象实现的接口的类型
         *      InvocationHandler h      //事件处理器
         */
         return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                before();
                Object invoke = method.invoke(target, args);
                after();
                return invoke;
            }
        });
    }

    // 调用方法之前执行
    private void before() {
        System.out.println("JDK动态代理发现异常......");
    }

    // 调用方法之后执行
    private void after() {
        System.out.println("JDK动态代理处理异常.......");
    }
}

运行程序:

/**
     * 代理模式角色:
     * Subject(抽象主题):代理类和真实主题的公共对外方法,也是代理类代理真实主题相同的接口;
     * RealSubject(真实主题):真正实现业务逻辑的类;
     * Proxy(代理主题):用来代理和封装真实主题;要与被代理类实现相同的接口Subject
     */
    public static void main(String[] args) {
        /**
         * jdk动态代理 是利用反射机制生成一个实现代理接口的匿名类。
         *  1. jdk动态代理主要是针对接口,要求目标对象必须实现接口,不能针对类。
         *          要求目标对象必须实现接口
         *          要求目标对象必须实现接口
         *          要求目标对象必须实现接口
         *  2. 动态代理是在运行时动态生成的,编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中
         */
        //JDK动态代理方法测试
        UserService userService = new UserServiceImpl();
        UserService proxy = (UserService) new JdkProxy(userService).getProxyInstance();
        proxy.report();

    }

结果查看
![在这里插入图片描述](https://img-blog.csdnimg.cn/6f991c556ad544d4a510cee44dc9e4d7.png
CGLIB动态代理代码实现
导入坐标

 <!--cglib动态代理-->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.5</version>
        </dependency>

编写一个UserService类也就是RealSubject(真实主题) 无需实现接口,无需实现接口

public class UserService {
    //汇报
    public void report() {
        System.out.println("CGLIB动态代理汇报异常.....");
    }
}

编写CGLIB动态代理类,也就是Proxy(代理主题)

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * CGLib动态代理 底层采用ASM字节码生成框架,使用字节码技术生成代理类比反射效率高。
 * 1. CGLib动态代理运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。
 * 2. CGLib动态代理是针对类,无需实现接口,对指定的类生成一个子类,覆盖其中的方法,达到代理类无侵入。
 * 3. CGLib动态代理是动态生成被代理类的子类,所以被final修饰的方法不能进行CGLib代理。
 */
public class CglibProxy implements MethodInterceptor {

    private Object target;//维护一个目标对象

    public CglibProxy(Object target) {
        this.target = target;
    }

   //为目标对象生成代理对象
    public Object getProxyInstance() {
        //工具类
        Enhancer en = new Enhancer();
        //将目标类设置父类
        en.setSuperclass(target.getClass());
        //设置回调函数
        en.setCallback(this);
        //创建代理对象
        return en.create();
    }

    /**
     *
     * @param o   生成的代理对象
     * @param method 被代理对象方法
     * @param objects 方法参数
     * @param methodProxy 代理方法
     * @return
     * @throws Throwable
     */
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object invoke = method.invoke(target, objects);
        after();
        return invoke;
    }
    // 调用方法之前执行
    private void before() {
        System.out.println("CGLIB动态代理发现异常......");
    }

    // 调用方法之后执行
    private void after() {
        System.out.println("CGLIB动态代理处理异常.......");
    }

}

运行程序:

 /**
     * 代理模式角色:
     * Subject(抽象主题):代理类和真实主题的公共对外方法,也是代理类代理真实主题相同的接口;
     * RealSubject(真实主题):真正实现业务逻辑的类;
     * Proxy(代理主题):用来代理和封装真实主题;要与被代理类实现相同的接口Subject
     */
    public static void main(String[] args) {
        /**
         * CGLib动态代理 底层采用ASM字节码生成框架,使用字节码技术生成代理类比反射效率高。
         * 1. CGLib动态代理运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。
         * 2. CGLib动态代理是针对类,无需实现接口,对指定的类生成一个子类,覆盖其中的方法,达到代理类无侵入。
         * 3. CGLib动态代理是动态生成被代理类的子类,所以被final修饰的方法不能进行CGLib代理。
         */
        //CGLib动态代理方法测试
        UserService userService = new UserService();
        UserService proxy = (UserService) new CglibProxy(userService).getProxyInstance();
        proxy.report();

    }

结果查看:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值