JDK动态代理

JDK动态代理用处

以下一段代码,需要加入权限验证和日志记录
public AirticleService{
    public List<Airticle> getAirticleList(){...}
    public Airticle getAirticle(String rtid){...}
    public String deleteAirticle(String rtid){...}
}
面对这种需求,我们常规的处理方案是:直接在类方法中编写权限验证和日志记录的代码。
但是,如果我们有很多Java类都需要作权限验证和日志记录呢?
我们是否要在每一个有需求的Java类中都加入权限验证的日志记录的代码呢(很多时候,每个类中的日志和权限验证的代码都是相同的)?
常规的方式,虽然能完成需求,但是带来了很多重复的工作,加上在业务代码中加入了很多非业务的代码(比如日志记录的代码就不是业务代码),使得代码的维护难度大大提升。
再者,如果某一天,用户要求我们将权限验证和日志记录的代码移除掉呢?那么,我们是否得一个个从Java类中把相关代码删掉或者注释掉呢?
JDK动态代理,就可以完美地解决上述的问题。

JDK动态代理实现原理

1、动态代理开发步骤
1、定义接口
2、编写接口实现类
3、编写代理工厂类
   代理类具体实现
   3.1 生成目标对象(可以通过对数直接传递目标对象或者目标对象Class)
   3.2 编写切面对象(切面对象包含目标对象)
   3.3 生成代理对象(代理对象其实是目标对象所对应的接口的子类,与目标对象拥有相同的父类)
4、使用代理工厂获取目标对象
2、动态代理实现原理
我们回想一下动态代理的使用步骤,为什么动态代理要返回与目标对象有相同父类的对象,而不是直接返回目标对象?
以下是调用流程图
user --->  proxy ---> 切面 --- > targer
以下是伪代
interface{ 接口方法 }
目标类 implements interface{}
代理工厂{
    创建代理对象方法(目标类型)
        目标对象 = 目标类型[反射创建实例];
        切面类对象 = 构造器(目标对象);
        代理对象 = JDK动态代理创建(目标类型接口参数,切面对象);
    }
    切面类{
        构造器(目标对象);
        执行(代理对象,执行方法,执行参数){
            [自定义代码]
            [反射执行]目标对象;
            [自定义代码]
        }
    }
}
InterfaceTarget的父类,ProxyTarget也是Interface的子类,Target是用户编码的代码,动态代理无法必定Target类,但是ProxyTarget是动态代理生成的类,其代码完全由代理自己控制。用户调用proxytargetproxytarget调用切面代码,切面代码再调用target。这样子,用户调用代理对象时候就相当于调用目标对象一样。

源码例子

1、定义接口
package com.example.springboot.demo.protxy;

public interface LoginService {
    public String login(String loginname, String password);

    public String unLogin(String credit);

    public Long getOnLineTime(String credit);
}
2、实现接口
package com.example.springboot.demo.protxy;

public class LoginServiceImpl implements LoginService {

    @Override
    public String login(String loginname, String password) {
        return "credit0001";
    }

    @Override
    public String unLogin(String credit) {
        return "unlogin sucesss";
    }

    @Override
    public Long getOnLineTime(String credit) {
        return 6000000L;
    }

}
3、编写代理类
package com.example.springboot.demo.protxy;

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

public class LoginProxy {

    @SuppressWarnings("unchecked")
    public static <T> T getLoginService(Class<T> cls) throws InstantiationException, IllegalAccessException {
        T newInstance = cls.newInstance();
        LoginInvocationHandler h = new LoginInvocationHandler(newInstance);
        return (T) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h);
    }

    static class LoginInvocationHandler implements InvocationHandler {
        private Object target;

        public LoginInvocationHandler(Object t) {
            target = t;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object invoke = method.invoke(target, args);
            return invoke;
        }

    }
}
4、编写测试类
package com.example.springboot.demo.protxy;

public class MainTest {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        LoginService loginService = LoginProxy.getLoginService(LoginServiceImpl.class);
        System.out.println(loginService.login("923339832", "winway"));
        System.out.println(loginService.unLogin("credit0001"));
        System.out.println(loginService.getOnLineTime("credit0001"));
        System.out.println(loginService);
        System.out.println(loginService.getClass());
        System.out.println(loginService.getClass().getSuperclass());
        System.out.println(loginService.getClass().getSuperclass().getSuperclass());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值