自我学习+整理--Java代理模式

代理模式

静态代理:

  1. 定义业务接口
  2. 被代理类实现业务接口
  3. 代理类实现业务接口
  4. 然后调用

静态代理例子:

  1. 需要创建一个共同实现的接口:
package com.lzl.proxy;

public interface IUserService {
    void add(String name);
}
  1. 创建被代理类:
package com.lzl.proxy.impl;

import com.lzl.proxy.IUserService;

/**
 * 被代理类
 */
public class UserServiceImpl implements IUserService {
    @Override
    public void add(String name) {
        System.out.println("添加用户:  "+name);
    }
}
  1. 创建代理类,并将被代理类通过构造方法注入,并实现相同的接口:
package com.lzl.proxy.impl;

import com.lzl.proxy.IUserService;

public class UserServiceProxy implements IUserService {
    private IUserService service;

    public UserServiceProxy(IUserService service) {
        this.service = service;
    }

    @Override
    public void add(String name) {
        System.out.println("开启数据库。。。");
        service.add(name);
        System.out.println("关闭数据库。。。");
    }
}
  1. 测试类:
public class Client {
    public static void main(String[] args) {
        IUserService userService = new UserServiceImpl();
        IUserService userService1 = new UserServiceProxy(userService);
        userService1.add("xxx");

静态代理的缺点:

  1. 代理类和被代理类都需要实现相同的接口
  2. 代理类型单一,维护复杂

动态代理(JDK动态代理):

  1. 创建被代理接口和类
  2. 创建InvocationHandler接口的实现类,在invoke方法中实现代理逻辑
  3. 通过Proxy的静态方法newProxyInstance( ClassLoaderloader, Class[] interfaces, InvocationHandler h) 创建一个代理对象
  4. 使用代理对象

动态代理例子:

  1. 还是先创建一个接口,并写出这个接口的实现类
  2. 直接编写测试类:
package com.lzl.proxy;

import com.lzl.proxy.impl.UserHandler;
import com.lzl.proxy.impl.UserServiceImpl;
import com.lzl.proxy.impl.UserServiceProxy;

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

public class Client {
    public static void main(String[] args) {
//        IUserService userService = new UserServiceImpl();
//        IUserService userService1 = new UserServiceProxy(userService);
//        userService1.add("lzl");
        IUserService iUserService = new UserServiceImpl();
        UserHandler userHandler = new UserHandler(iUserService);
        //第一个参数:被代理类的类加载器
        //第二个参数:被理类需要实现的接口(传入被代理类实现的接口,这样代理类和被代理类都实现了相同的接口)
        //第三个参数:invocation handler,用来处理方法的调用,传入我们自己实现的handler,这个方法中实现代理
        IUserService o = (IUserService) Proxy.newProxyInstance(new UserServiceImpl().getClass().getClassLoader(), iUserService.getClass().getInterfaces(), userHandler);
        o.add("lzl");

        IUserService o1 = (IUserService) Proxy.newProxyInstance(iUserService.getClass().getClassLoader(),
                iUserService.getClass().getInterfaces(),
                (proxy, method, args1) -> {
                    System.out.println("运行开始。。。");
                    Object invoke = method.invoke(iUserService, args1);
                    System.out.println("运行结束。。。");
                    return invoke;
                }
        );
        o1.add("hhaah");

    }
}

基于cglib实现动态代理:

只要被代理类不是最终类(final修饰)就可使用,由于cglib是第三方技术,需要导入jar包或者maven导入坐标:

<dependencies>
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.3.0</version>
    </dependency>
</dependencies>

创建一个需要被代理的类:

package com.lzl.proxy.impl;

import com.lzl.proxy.IUserService;

/**
 * 被代理类
 */
public class CglibUserService {
    public void add(String name) {
        System.out.println("添加用户:  "+name);
    }
}

直接编写测试类:

package com.lzl.proxy.impl;

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

import java.lang.reflect.Method;

public class CglibDemo {
    public static void main(String[] args) {
        //创建一个目标类对象
        CglibUserService cglibUserService = new CglibUserService();
        //使用cglib创建代理对象
        //参数:
        //class type : 指定我们要代理的目标类的字节码对象,指定目标类的类型
        //Callback  : 回调,意思是我们提供一个方法,它会在合适的时候回调,由于该接口只是一个名称定义没有具体的抽象方法,所以一般是使用它的子接口
        //MethodInterceptor(方法拦截器)
        CglibUserService o = (CglibUserService) Enhancer.create(cglibUserService.getClass(), new MethodInterceptor() {
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("方法执行。。。");
                Object invoke = method.invoke(cglibUserService, args);
                System.out.println("方法结束。。。");
                return invoke;
            }
        });
        o.add("lzl");
    }
}

MethodInterceptor(方法拦截器),它的抽象方法:

Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
参数:
Var1是代理对象的引用,也是返回值
Var2是执行的method方法
Var3是参数列表
Var4方法的代理参数

Cglib是基于父类的动态代理,是在内存中生成了一个对象,该对象继承了原对象,所以生成的对象是目标类对象的子类。

因为jdk动态代理要求比较多,更加难实现。

Cglib>jdk proxy>动态>静态

Spring里默认是根据被代理类是否实现接口来进行选择动态代理模式:如果实现了接口就是用jdk的proxy代理;如果没有实现接口,就是用cglib进行动态代理

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

so_defficult

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值