动态代理和cglib代理

动态代理

动态代理是由java内部的反射机制来实现的,被代理对象必须要实现接口,才能产生代理对象.如果没有接口将不能使用动态代理技术

例子

  • 编写一个接口,包含了增删改查4个方法
package cn.itcast.service;

public interface UserService {
    void save();
    void delete();
    void update();
    void find();
}
  • 编写该接口的实现类
    如果单纯的对每个方法都进行打开事物和提交事物,一旦方法很多,就会很繁琐,所以就使用动态代理技术,产生一个代理对象,代理对象帮我们增强代码。
package cn.itcast.service;

public class UserServiceImpl implements UserService {
    @Override
    public void save() {
        //System.out.println("打开事物!");
        System.out.println("保存用户!");
        //System.out.println("提交事物!");
        //int i = 1/0;
    }
    @Override
    public void delete() {
        System.out.println("删除用户!");
    }
    @Override
    public void update() {
        System.out.println("更新用户!");
    }
    @Override
    public void find() {
        System.out.println("查找用户!");
    }
}
  • 编写一个动态代理的类
    需要实现InvocationHandler接口
package cn.itcast.c_proxy;

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

import cn.itcast.service.UserService;
import cn.itcast.service.UserServiceImpl;
public class UserServiceProxyFactory implements InvocationHandler {
    private UserService us;
    //在创建代理类的时候,将需要代理的类传递过来,进行增强
    public UserServiceProxyFactory(UserService us) {
        super();
        this.us = us;
    }
    //自定义一个方法,用于产生一个动态代理对象
    public UserService getUserServiceProxy(){
    //newProxyInstance()包含了三个参数
    //第一个是当前类的类加载器,第二个是需要被代理的类的接口,第三个是InvocationHandler接口(这里我们实现了这个接口,直接使用this即可)
        UserService usProxy = (UserService) Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(),
                                    UserServiceImpl.class.getInterfaces(), 
                                    this);
        //返回当前代理对象
        return usProxy;

    }
    //重写InvocationHandler中的方法,用于增强代理对象中的方法
    //invoke包含三个参数,第一个是当前的代理对象,第二个是当前调用的方法,当前方法执行时的参数
    @Override
    public Object invoke(Object arg0, Method method, Object[] arg2) throws Throwable {
        System.out.println("打开事务!");
        //invoke方法的执行需要当前方法所在对象的实例
        Object invoke = method.invoke(us, arg2);//这里代表着,执行被代理对象中原有的方法
        System.out.println("提交事务!");
        return invoke;
    }
}
  • 测试
@Test
    //动态代理
    public void fun1(){
        UserService us = new UserServiceImpl();
        UserServiceProxyFactory factory = new UserServiceProxyFactory(us);
        UserService usProxy = factory.getUserServiceProxy();
        usProxy.save();
        //代理对象与被代理对象实现了相同的接口
        //代理对象 与 被代理对象没有继承关系,是兄弟关系
        System.out.println(usProxy instanceof UserServiceImpl );//false
    }

Cglib代理(了解)

cglib动态代理底层则是借助asm来实现的。第三方代理技术,cglib代理.可以对任何类生成代理.代理的原理是对目标对象进行继承代理. 如果目标对象被final修饰.那么该类无法被cglib代理。

  • 编写Cglib代理类
package cn.itcast.c_proxy;

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

import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import cn.itcast.service.UserService;
import cn.itcast.service.UserServiceImpl;

//观光代码=>cglib代理
public class UserServiceProxyFactory2 implements MethodInterceptor {


    public UserService getUserServiceProxy(){

        Enhancer en = new Enhancer();//帮我们生成代理对象

        en.setSuperclass(UserServiceImpl.class);//设置对谁进行代理

        en.setCallback(this);//代理要做什么

        UserService us = (UserService) en.create();//创建代理对象

        return us;
    }

    @Override
    public Object intercept(Object prxoyobj, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable {
        //打开事务
        System.out.println("打开事务!");
        //调用原有方法
        Object returnValue = methodProxy.invokeSuper(prxoyobj, arg);
        //提交事务
        System.out.println("提交事务!");
        return returnValue;
    }
}
  • 测试
@Test
    public void fun2(){

        UserServiceProxyFactory2 factory = new UserServiceProxyFactory2();

        UserService usProxy = factory.getUserServiceProxy();

        usProxy.save();

        //判断代理对象是否属于被代理对象类型
        //代理对象继承了被代理对象=>true
        System.out.println(usProxy instanceof UserServiceImpl );//true
    }

结论

总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。由此可以看出,jdk动态代理有一定的局限性,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。。

猜你喜欢

转载自blog.csdn.net/qq_42780864/article/details/81363414
今日推荐