动态代理之jdk代理

java中加载一个类,需要把.java源文件编译成.class文件,然后在把.class文件通过类加载器,装载到JVM虚拟机中。大部分情况下,我们的类都是通过这种静态加载编译后的.class文件生成的。此时在项目工程下的target文件夹中,都会有相应的.class文件。但动态代理则不一样,java文件和.class文件都是不可见的。通过代理技术会生成我们需要的java文件,然后在编译成.class文件,最后通过类加载器把相应的.class文件加载到jvm内存中,加载完毕后会把这些java和.class文件删掉。此时在工程中,看不到任何代理生成的相关文件。但我们想要的功能的确帮我们实现了。

java中动态代理技术主要有以下两种

  1. jdk动态代理(实现InvocationHandle接口)
  2. cglib代理(继承类)

jdk动态代理

通过模仿mybatis DAO 来记录下jdk动态代理过程。

  1. 定义一个dao接口
  2. 定义一个实现InvocationHandle接口的类
  3. 创建一个代理工厂类

需求:模仿mybatis 实现用户的查询和新增功能

定义DAO接口

public interface UserDao {
    @Select("select * from xx")
     void query();
    @Insert("insert user(id,name) values(id,name)")
     void insert();
}

创建一个UserDao接口,里面包含两个方法,query()和insert()方法。其中每个方法上面用了自定义注解修饰。功能类比mybatis中的xml 配置。

@Select

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Select {
    String[] value();
}

@Insert

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Insert {
    String[] value();
}

实现InvocationHandle接口

public class UserDaoProx implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        if (method.isAnnotationPresent(Select.class)) {
            System.out.println("开始查询.....");
            Select annotation = method.getAnnotation(Select.class);
            String[] value = annotation.value();
            if (value.length > 0) {
                System.out.println(value[0]);
            }
        } else if (method.isAnnotationPresent(Insert.class)) {
            System.out.println("开始插入.....");
            Insert annotation = method.getAnnotation(Insert.class);
            String[] value = annotation.value();
            if (value.length > 0) {
                System.out.println(value[0]);
            }
        }
        return null;
    }

}

这里对要代理的方法做了判断,获取方法相应注解的value,然后打印sql语句

创建代理工厂类

public class MyProxyFactory {
    public static Object getProxyObject(Class clazz){
       return Proxy.newProxyInstance(MyProxyFactory.class.getClassLoader(),new Class[] 
       {clazz},new UserDaoProx());
    }
}

jdk动态代理运用了Proxy的newProxyInstance()方法,帮我们完成创建代理类并完成编译和加载到jvm内存中这一过程。原理就是干了我们编译器的事。

newProxyInstance()方法有三个参数

  1. ClassLoader loader:类加载器
  2. Class[] interfaces:要代理的接口
  3. InvocationHandler h:接口方法的回调。这个也是为什么要定义一个实现InvocationHandle接口的原因

测试类

public class App 
{
    public static void main( String[] args )  {
        UserDao userDao = (UserDao) MyProxyFactory.getProxyObject(UserDao.class);
        userDao.query();
        userDao.insert();
    }
}

用我们创建的代理工厂方法,帮我们创建一个UserDao实现。调用query和insert方法。看后台打印

目前已完成运用jdk动态代理技术模仿mybatis的DAO功能。

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值