静态代理和动态代理详解

2 篇文章 0 订阅

代理模式(Proxy)是通过代理对象访问目标对象,这样可以在目标对象基础上增强额外的功能,如添加权限,访问控制和日志等功能。

Java代理分为静态代理和动态代理和Cglib代理,下面进行逐个说明。
1.静态代理
接口类AdminService.java接口

package com.example.demo.study.proxy.staticProxy;

public interface AdminService {

    /**
     * 获取用户名称
     * @return
     */
    String getUserName();

    /**
     * 添加用户
     * @return
     */
    boolean addUser();
}

实现类AdminServiceImpl.java

package com.example.demo.study.proxy.staticProxy;

/**
 * @Description: 真实对象实现类
 * @ClassName: AdminServiceImpl
 * @Author zhaomx
 * @Version 1.0
 * @Date 2021-03-18 10:56
 */
public class AdminServiceImpl implements AdminService {

    @Override
    public String getUserName() {
        System.out.println("我是超级管理员用户");
        return "我是超级管理员用户";
    }

    @Override
    public boolean addUser() {
        System.out.println("添加成功了");
        return true;
    }
}

代理类AdminServiceProxy.java

package com.example.demo.study.proxy.staticProxy;

/**
 * @Description: AdminService的静态代理类
 * @ClassName: AdminServiceProxy
 * @Author zhaomx
 * @Version 1.0
 * @Date 2021-03-18 11:01
 */
public class AdminServiceProxy implements AdminService {

    private AdminService adminService;

    public AdminServiceProxy(AdminService adminService) {
        this.adminService = adminService;
    }

    public String getUserName() {
        System.out.printf("我是静态代理,呜呜呜 方法:%s\n", "getUserName");
        return adminService.getUserName();
    }

    public boolean addUser() {
        System.out.printf("我是静态代理,呜呜呜 方法:%s\n", "addUser");
        return adminService.addUser();
    }
}

测试类StaticProxyTest.java

package com.example.demo.study.proxy.staticProxy;

/**
 * @Description:
 * @ClassName: MainTest
 * @Author zhaomx
 * @Version 1.0
 * @Date 2021-03-18 11:05
 */
public class StaticProxyTest {

    public static void main(String[] args) {

        AdminService adminService = new AdminServiceImpl();

        AdminServiceProxy adminServiceProxy = new AdminServiceProxy(adminService);

        adminServiceProxy.getUserName();
        adminServiceProxy.addUser();
        System.out.println("结束啦~~~~~~~~~~~~~~~~");
    }
}

输出:
在这里插入图片描述

总结:

静态代理模式在不改变目标对象的前提下,实现了对目标对象的功能扩展。
不足:静态代理实现了目标对象的所有方法,一旦目标接口增加方法,代理对象和目标对象都要进行相应的修改,增加维护成本。

2.JDK动态代理
为解决静态代理对象必须实现接口的所有方法的问题,Java给出了动态代理,动态代理具有如下特点:

1.Proxy对象不需要implements接口;
2.Proxy对象的生成利用JDK的Api,在JVM内存中动态的构建Proxy对象。需要使用java.lang.reflect.Proxy类的
方法,方法参数说明:
a.ClassLoader loader:指定当前target对象使用类加载器,获取加载器的方法是固定的;
b.Class<?>[] interfaces:target对象实现的接口的类型,使用泛型方式确认类型
c.InvocationHandler invocationHandler:事件处理,执行target对象的方法时,会触发事件处理器的方法,会把当前执行target对象的方法作为参数传入。

2.1 实战代码:
AdminServiceImpl.java和AdminService.java和原来一样,这里不再赘述。

AdminServiceInvocation.java

package com.example.demo.study.proxy.dynamicProxy;

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

/**
 * @Description: 重写时间处理器方法
 * @ClassName: AdminServiceInvocation
 * @Author zhaomx
 * @Version 1.0
 * @Date 2021-03-18 11:27
 */
public class AdminServiceInvocation implements InvocationHandler {

    private Object target;

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

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("判断用户是否有权限进行操作");
        Object object = method.invoke(target);
        System.out.println("记录用户执行操作的用户信息、更改内容和时间等");
        return object;
    }
}

AdminServiceDynamicProxy.java

package com.example.demo.study.proxy.dynamicProxy;

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

/**
 * @Description: jdk动态代理类
 * @ClassName: AdminServiceDynamicProxy
 * @Author zhaomx
 * @Version 1.0
 * @Date 2021-03-18 11:31
 */
public class AdminServiceDynamicProxy {

    private Object target;
    private InvocationHandler invocationHandler;

    public AdminServiceDynamicProxy(Object target, InvocationHandler invocationHandler) {
        this.target = target;
        this.invocationHandler = invocationHandler;
    }

    public Object newProxyInstance() {
        Object obj = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), invocationHandler);
        return obj;
    }
}

DynamicProxyTest.java

package com.example.demo.study.proxy.dynamicProxy;

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

/**
 * @Description:
 * @ClassName: DynamicProxyTest
 * @Author zhaomx
 * @Version 1.0
 * @Date 2021-03-18 11:36
 */
public class DynamicProxyTest {

    public static void main(String[] args) {
        //方法一,使用自定义动态代理类
        AdminService adminService = new AdminServiceImpl();
        AdminServiceInvocation adminServiceInvocation = new AdminServiceInvocation(adminService);

        AdminServiceDynamicProxy adminServiceDynamicProxy = new AdminServiceDynamicProxy(adminService, adminServiceInvocation);
        AdminService proxy = (AdminService) adminServiceDynamicProxy.newProxyInstance();
        proxy.addUser();
        proxy.getUserName();
        System.out.println("=============================================");

        //方法二
        AdminService proxy2 = (AdminService) Proxy.newProxyInstance(adminService.getClass().getClassLoader(), adminService.getClass().getInterfaces(), adminServiceInvocation);
        proxy2.addUser();
        proxy2.getUserName();
        System.out.println("=============================================");

        //方法三
        AdminService proxy3 = (AdminService) Proxy.newProxyInstance(adminService.getClass().getClassLoader(), adminService.getClass().getInterfaces(), new InvocationHandler() {

            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("判断用户是否有权限进行操作");
                Object obj = method.invoke(adminService, args);
                System.out.println("记录用户执行操作的用户信息、更改内容和时间等");
                return obj;
            }
        });
        proxy2.addUser();
        proxy2.getUserName();
    }
}

输出结果:
在这里插入图片描述
3.Cglib代理

JDK动态代理要求target对象是一个接口的实现对象,假如target对象只是一个单独的对象,并没有实现任何接口,这时候就会用到Cglib代理(Code Generation Library),即通过构建一个子类对象,从而实现对target对象的代理,因此目标对象不能是final类(报错),且目标对象的方法不能是final或static(不执行代理功能)

Cglib依赖的jar包:

<!--引入Cglib动态代理-->
		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>3.2.10</version>
		</dependency>

3.1实战
目标对象类AdminCglibService.java

package com.example.demo.study.proxy.cglib;

/**
 * @Description:
 * @ClassName: AdminCglibService
 * @Author zhaomx
 * @Version 1.0
 * @Date 2021-03-18 13:53
 */
public class AdminCglibService {

    public String getUserName() {
        System.out.println("我是超级管理员用户");
        return "我是超级管理员用户";
    }

    public boolean addUser() {
        System.out.println("添加成功了");
        return true;
    }
}

代理类AdminServiceCglibProxy.java

package com.example.demo.study.proxy.cglib;

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

import java.lang.reflect.Method;

/**
 * @Description: cglib动态代理类
 * @ClassName: AdminServiceCglibProxy
 * @Author zhaomx
 * @Version 1.0
 * @Date 2021-03-18 13:54
 */
public class AdminServiceCglibProxy implements MethodInterceptor {

    private Object target;

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

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

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("判断用户是否有权限进行操作");
        Object obj = method.invoke(target);
        System.out.println("记录用户执行操作的用户信息、更改内容和时间等");
        return obj;
    }
}

Cglib代理测试类CglibProxyTest.java

package com.example.demo.study.proxy.cglib;

/**
 * @Description:
 * @ClassName: CglibProxyTest
 * @Author zhaomx
 * @Version 1.0
 * @Date 2021-03-18 13:56
 */
public class CglibProxyTest {

    public static void main(String[] args) {

        AdminCglibService target = new AdminCglibService();
        AdminServiceCglibProxy proxyFactory = new AdminServiceCglibProxy(target);
        AdminCglibService proxy = (AdminCglibService)proxyFactory.getProxyInstance();

        System.out.println("代理对象:" + proxy.getClass());

        Object obj = proxy.addUser();
        System.out.println("find 返回对象:" + obj.getClass());
        System.out.println("----------------------------------");
        proxy.addUser();
        proxy.getUserName();
    }
}

输出结果:
在这里插入图片描述

总结
理解上述Java代理后,也就明白Spring AOP的代理实现模式,即加入Spring中的target是接口的实现时,就使用JDK动态代理,否是就使用Cglib代理。Spring也可以通过<aop:config proxy-target-class=“true”>强制使用Cglib代理,使用Java字节码编辑类库ASM操作字节码来实现,直接以二进制形式动态地生成 stub 类或其他代理类,性能比JDK更强。

文章引用:https://www.jianshu.com/p/8ccdbe00ff06

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值