静态代理和静态代理(Jdk动态代理和Cglib动态代理)

静态代理

代理对象的两个概念:
1、代理对象存在的价值主要用于拦截对真实业务对象的访问。
2、代理对象应该具有和目标对象(真实业务对象)相同的方法。

/**
 * @author acoffee
 * @create 2021-11-16 9:49
 */
//接口
interface Cookie{
    void cooking();
}

//实现类
class CookieImpl implements Cookie{

    @Override
    public void cooking() {
        System.out.println("煮饭!");
    }
}

//代理类
class StaticProxy{
    private Cookie cookie;
    public StaticProxy(Cookie cookie){
        this.cookie = cookie;
    }

    public void cooking(){
        System.out.println("洗菜!");
        cookie.cooking();
        System.out.println("洗碗!");
    }
}

//测试类
public class StaticProxyTest {
    public static void main(String[] args) {
        StaticProxy staticProxy = new StaticProxy(new CookieImpl());
        staticProxy.cooking();
    }
}

执行结果:
在这里插入图片描述

上述代码
在这里插入图片描述
静态代理的缺点:
一个代理类只能为一个接口服务,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。 如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。原因就是代理类和目标对象的类都是在编译期间就已经确定下来了,不利于程序的扩展。

最好就是让一个代理类完成所有的代理,所以就有了我们的动态代理。

动态代理

动态代理分为两种:
① JDK动态代理
② CGLIB 动态代理

Spring Aop底层就是用的这两种代理

① JDK动态代理

JDK动态代理: 利用 反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

JDK动态代理主要是依赖java.lang.reflect的Proxy类和InvocationHandler接口,

Proxy类中我们主要是调用Proxy类中的newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法可以创建一个动态代理对象,但是这个方法需要3个参数,前两个参数是固定的,但第三个参数比较麻烦,需要我们创建一个类MyInvocationHandler来实现InvocationHandler接口,这个类里面要重写invoke()方法,我们这里为了方便是使用的匿名内部类。

/**
 * @author acoffee
 * @create 2021-11-16 13:56
 */
 
//接口类
interface CookieService{
    void cooking();
}

//实现类
class CookieServiceImpl implements CookieService{

    @Override
    public void cooking() {
        System.out.println("煮饭!");
    }

}

//JDK代理类
class JdkDynamicProxy{
   public Object getProxyObject(Object targetClass) {
        Object proxyInstance = Proxy.newProxyInstance(targetClass.getClass().getClassLoader(), targetClass.getClass().getInterfaces(),
                //InvocationHandler:我们这里使用lambda表达式,他是一个函数式接口
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("洗菜!");
                        Object invoke = method.invoke(targetClass, args);
                        System.out.println("洗碗!");
                        return invoke;
                    }
                });
		        /**InvocationHandler:我们这里使用lambda表达式,他是一个函数式接口
		         (Object proxy, Method method, Object[] args) -> {
		         System.out.println("洗菜!");
		         Object invoke = method.invoke(targetClass, args);
		         System.out.println("洗碗!");
		         return invoke;
		         });*/
        return proxyInstance;
    }
}


//测试类
public class JdkDynamicTest {
    @Test
    public void testJdk(){
        CookieService cookieService = new CookieServiceImpl();
        JdkDynamicProxy jdkDynamicProxy = new JdkDynamicProxy();
        CookieService proxyObject = (CookieService) jdkDynamicProxy.getProxyObject(cookieService);
        proxyObject.cooking();
    }
}

执行结果:
在这里插入图片描述

② CGLIB 动态代理

CGlib动态代理: 利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

/**
 * @author acoffee
 * @create 2021-11-21 18:17
 */
//被代理类
class CookieServiceImpl {
    public void cooking() {
        System.out.println("煮饭!");
    }
}

//代理类
class CglibDynamic {

    public Object getProxyObject(Object targetClass) {
    	//这里是不能使用Lambda表达式,因为这里第二个参数需要的是Callback接口,因为Callback不是函数式接口
    	//我们这里可以写InvocationHandler接口的原因是因为public interface InvocationHandler extends Callback
    	//InvocationHandler 接口继承了Callback 接口
        Object obj = Enhancer.create(targetClass.getClass(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("洗菜!");
                Object invoke = method.invoke(targetClass, args);
                System.out.println("洗碗!");
                return invoke;
            }
        });
        return obj;
    }
}

//测试类
public class CglibDynamicTest {
    @Test
    public void testCglib() {
        CglibDynamic cglibDynamic = new CglibDynamic();
        CookieServiceImpl proxyObject = (CookieServiceImpl) cglibDynamic.getProxyObject(new CookieServiceImpl());
        proxyObject.cooking();
    }
}

JDK动态代理 VS Cglib动态代理

JDK动态代理和cglib动态代理有什么区别?

JDK动态代理智能对实现了接口的类生成代理对象;
Cglib可以对任意类生成代理对象,它的原理是对目标对象进行继承代理,如果目标对象被final修饰,那么该类无法被Cglib代理。

JDK动态代理

1、因为利用JDKProxy生成的代理类实现了接口,所以目标类中所有的方法在代理类中都有。
2、生成的代理类的所有的方法都拦截了目标类的所有的方法。而拦截器中invoke方法的内容正好就是代理类的各个方法的组成体。
3、利用JDKProxy方式必须有接口的存在。
4、invoke方法中的三个参数可以访问目标类的被调用方法的API、被调用方法的参数、被调用方法的返回类型。

cglib动态代理

1、 Cglib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。
2、 用Cglib生成代理类是目标类的子类。
3、 用Cglib生成 代理类不需要接口
4、 用Cglib生成的代理类重写了父类的各个方法。
5、 拦截器中的intercept方法内容正好就是代理类中的方法体

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值