Java设计模式-动态代理

一、实现方式有哪些?

1.基于接口实现:JDK动态代理
2.基于类实现:cglib方式
3.基于java字节码方式:javasist

二、JDK动态代理实现

一、定义一个接口 UserService

public interface UserService {

    void add();
    
    void delete();
    
    void update();
    
    void select();

}

二、添加实现

public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }

    @Override
    public void update() {
        System.out.println("修改了一个用户");
    }

    @Override
    public void select() {
        System.out.println("查询了一个用户");
    }
}

三、测试接口方法

public class ProxyTest01 {
    
    public static void main(String[] args) {

        UserService userService = new UserServiceImpl();

        userService.add();
        userService.delete();
        userService.update();
        userService.select();

    }
}

在这里插入图片描述
假设现在有一个需求:在每个方法执行前后打印调用时间。
现在能想到的办法就是:
1.直接修改源代码(造成代码冗余)
2.用静态代理(代码复用性低)
3.动态代理(相对较好)

四、如何用动态代理实现该需求?
编写一个可以创建代理的类,实现InvocationHandler接口


public class ProxyInvocationHandler implements InvocationHandler {

    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    /**
     * 该方法用户动态获取代理对象
     * @return
     */
    public Object getProxy(){
        return Proxy.newProxyInstance(getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

   //通过反射机制调用对象的方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        start(method.getName());
        Object result = method.invoke(target, args);
        end(method.getName());
        return result;
    }

    private void start(String msg){
        System.out.println("开始执行" + msg + "方法" + new Date().toString());
    }

    private void end(String msg){
        System.out.println("结束执行" + msg + "方法" + new Date().toString());
    }

}

五、创建测试类

public class Client {

    public static void main(String[] args) {

        //被代理的类
        UserServiceImpl userService = new UserServiceImpl();

        //设置动态代理
        ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
        proxyInvocationHandler.setTarget(userService);

        //通过反射机制获取动态代理的对象并强转
        UserService proxy = (UserService) proxyInvocationHandler.getProxy();
        //调用动态代理对象的方法
        proxy.add();
        proxy.update();
        proxy.delete();
        proxy.select();

    }

}

输出
在这里插入图片描述
通过动态代理实现了该需求。

 //通过反射机制调用对象的方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        start(method.getName());
        Object result = method.invoke(target, args);
        end(method.getName());
        return result;
    }

    private void start(String msg){
        System.out.println("开始执行" + msg + "方法" + new Date().toString());
    }

    private void end(String msg){
        System.out.println("结束执行" + msg + "方法" + new Date().toString());
    }

在执行代理对象的add、delete、update、select方式时,都是通过反射机制将方法体,实参传入invoke方法来执行,result就是实际的方法返回值,例如将add方法修改一下

//将接口与实现的add方法返回值修改为Integer类型
  @Override
    public Integer add() {
        System.out.println("增加了一个用户");
        return 1;
    }

但是我们可以在invoke方法中讲返回值进行二次处理

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        start(method.getName());
        Object result = method.invoke(target, args);
        end(method.getName());
        result = 10;
        return result;
    }

例如我们将返回值重新赋值为10
再次测试

 		Integer add = proxy.add();
        System.out.println("add方法的返回值" + add);
        proxy.update();
        proxy.delete();
        proxy.select();

结果:
在这里插入图片描述
发现返回值已经被修改。

猜你喜欢

转载自blog.csdn.net/qq_43750656/article/details/106406662