JDK动态代理心得

jdk动态代理讲解

今天看了一个文章顿时明白了jdk动态代理的一些东西,没事赶快记录一下。

之前看了很多关于动态代理文章,没有组织到一起,现在明白点,说一下,有说的不对的地方欢迎大家指出来  流水账开启。(这个教程适合懂一些,又不太明白的)

interface Mappers{
    @Select("select * from User where id =#{id} and name=${name}")
    List<Integer> selectAll(int id,String name);
}

public class Cesjo {
    public static void main(String[] args) {
        Mappers mappers = (Mappers) Proxy.newProxyInstance(Tesss.class.getClassLoader(), new Class<?>[]{Mappers.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Select annotation = method.getAnnotation(Select.class);
                String sourSql="";
                if(annotation.value() !=null && annotation.value().length>0){
                    sourSql=Arrays.toString(annotation.value());
                    System.out.println(Arrays.toString(annotation.value()));
                }
                Map<String, Object> map = buildParamert(method, args);
                String afterSql=replaceSql(sourSql,map);
                System.out.println(afterSql);
                return null;
            }
        });
    mappers.selectAll(100,"你好啊");
    }
    public static String replaceSql(String sourSql,Map<String ,Object> params){
        String afterSql[]={sourSql};
        params.forEach((s, o) -> {
            afterSql[0]=  afterSql[0].replaceAll(".\\{"+s+"\\}",o.toString());
        });
        return afterSql[0];
    }
    public static Map<String,Object> buildParamert(Method method, Object[] args){
        Map<String ,Object>  par=new HashMap<String ,Object>();
        Parameter[] parameters = method.getParameters();
        int index[]={0};
        if(parameters!=null && parameters.length>0){
            Arrays.asList(parameters).forEach(parameter -> {
                  par.put(parameter.getName(),args[index[0]++]);
            });
        }
        return par;
    }


}

看一下这个代码,这个是通过proxy动态代理生成的一个mepper对象实例。

先说newProxyInstance参数问题

1.该参数是一个类加载器,作用嘛就是通过类加载器,我们可以把一个class文件加载到内存中生成一个class的对象,这里并不是实例对象啊,是class对象。可以百度一下ClassLoader和class.forName的区别。

2.该参数就是传的一个class对象数组。这个数组里面放的是我们接口的类对象,通过这个class来实现。

3.这个参数是固定参数,是一个实现InvackHandler.接口里面可以写我们的需要去代理的方法。

再给大家看一段代码。这个网上也很多。

public interface Subject { // 定义代理接口
    String sayHello();
}

public class SubjectImpl implements Subject {  // 定义代理接口实现类
    @Override
    public String sayHello() {
        System.out.println(" Hello World");
        return "success";
    }
}

public class ProxyInvocationHandler implements InvocationHandler {  // 定义动态代理调用处理器
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(" 🧱 🧱 🧱 进入代理调用处理器 ");
        return method.invoke(target, args);
    }
}


public class ProxyTest {
    public static void main(String[] args) {
        Subject subject = new SubjectImpl();
        Subject proxy = (Subject) Proxy
                .newProxyInstance(
                        subject.getClass().getClassLoader(),
                        subject.getClass().getInterfaces(),
                        new ProxyInvocationHandler(subject));

        proxy.sayHello();
        /**
         * 打印输出如下
         * 调用处理器:🧱 🧱 🧱 进入代理调用处理器
         * 被代理实现类:Hello World
         */
    }
}

估计大家看过很多这样的代码吧,大家有没有好奇这种动态代理方式,为什么要写实现一个实现类,而我们在mybatis中却没有实现类。那是怎么搞的。带着这个问题给大家说一下。

动态代理有两种实现方式,一种是实现是上面写的那种,先实现一个接口的实现类,然后,在invockHander的实现类的invoke方法中通过注入target的方式用反射来调用。

第二种方式就是最开头的那种写法,并没有写被代理接口的实现类,这种方式。仅仅是调用了一下invoke这个方法。

所以说,动态代理的实现可以不用注入代理。

 

 

 

而在mybatis就是采用第二种方式,网上讲的大部分都是第一种方式,所以造成我太久的疑惑,

 

在proxy类里面有一个内部类叫ProxyClassFactory,这个类是生成我们被代理接口的实现类的,类名开始$proxy

 

 

其中有一个属性,我猜的啊,估计八九不离十 ,这个proxyClassFIle这个里面放的就是我们生成代理类的字符串。可以自己求证一下。

 

 

说几个mybaits中常见的问题:

  1. JDK 动态代理能否对类代理?
    因为 JDK 动态代理生成的代理类,会继承 Proxy 类,由于 Java 无法多继承,所以无法对类进行代理

     

  2. 抽象类是否可以 JDK 动态代理?
    不可以,因为jdk动态代理会检测被代理class是否为接口,都在java.lang包下面的。proxy这个类里面的。



     
  3. Mybatis Mapper 接口没有实现类,怎么实现的动态代理?

    上面已经说了,mybatis的动态代理没有注入被代理对象,仅仅是调用了invockHandler方法中的invoke方法。所以不需要。你懂了不。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值