静态代理和动态代理

文章目录


前言

代理是什么:

对代码进行改造,最先想到修改业务逻辑。但是现在要求不改原有代码,对代码进行增强。

静态代理是什么:

一般来说,那就重写个方法呗,里面再调用原有方法,那这个就是静态代理,此方式不适合代码扩展,一个接口只能有一个代理,代理类需要创建很多。

动态代理是什么:

那如果代理方法多了,静态代理重写的方法也就多了,如果每个方法增强功能都差不多,能不能重写成一个方法呢,这就是动态代理了,Java API提供了Proxy类用于接口实现(反射方式)。如果类没有实现接口,这就需要另一种CGLIB实现代理(继承方式)。


提示:以下是本篇文章正文内容,下面案例可供参考

一、静态代理

代码如下(示例):

public class UserServiceImpl implements UserService{//业务接口实现类
    @Override
    public void run() {
        System.out.println("实现方法");
    }
    public static void main(String[] args) {
        //静态代理
        UserServiceImpl_Static serviceImpl_static = new UserServiceImpl_Static();
        serviceImpl_static.run();
    }
}
interface UserService {//业务实现接口
    void run();
}
class UserServiceImpl_Static implements UserService {//静态代理
    private UserServiceImpl userService = new UserServiceImpl();
    @Override
    public void run() {
        System.out.println("静态增强");
        userService.run();
    }
}

二、动态代理

1.Java Proxy

Proxy.newProxyInstance()会生成$Proxy代理类,代理类对象继承Proxy类,并指定了参数为InvocationHandler的构造方法。

通过配置系统属性让代理对象的class类写入到磁盘:System.setPropertie("sun.misc.ProxyGenerator.saveGeneratedFiles","true");

也可以通过输出流方式写入到磁盘:

public static void main(String[] args) throws IOException {
    //文件路径:E:\IdeaProjects\test\src\main\java\$Proxy0.class
    getProxyClass("$Proxy0.class");
}
private static void getProxyClass(String fileName) throws IOException {
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(fileName, new Class[]{UserService.class}, 0);
    FileOutputStream fos = new FileOutputStream("E:\\IdeaProjects\\test\\src\\main\\java\\" + fileName);
    fos.write(proxyClassFile);
    fos.flush();
    fos.close();
}

代码如下(示例):

public class UserServiceImpl implements UserService{//业务接口实现类
    @Override
    public void run() {
        System.out.println("实现方法");
    }
    public static void main(String[] args) {
        //动态代理
        UserServiceImpl_Dynamic userServiceImpl_dynamic = new UserServiceImpl_Dynamic();
        UserService userService = (UserService)userServiceImpl_dynamic.get(new UserServiceImpl());
        userService.run();
    }
}
interface UserService {//业务实现接口
    void run();
}
class UserServiceImpl_Dynamic implements InvocationHandler {//动态代理
    private Object obj;

    public Object get(Object obj) {
        this.obj = obj;
        return Proxy.newProxyInstance(this.obj.getClass().getClassLoader(),this.obj.getClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("动态增强");
        return method.invoke(obj,args);
    }
}

2.CGLib

很多AOP的框架使用CGLib:Spring AOP和dynaop,Hibernate使用CGLIB来代理单端single-ended(多对一和一对一)关联。

通过System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"E:\\IdeaProjects\\test\\src\\main\\java\\cglib")输入代理类

代码如下(示例):

//所有非final修饰的方法 都可代理
public class UserServiceImpl{
    public void run() {
        System.out.println("run方法");
    }
    public static void main(String[] args) {
        //输出代理类
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"E:\\IdeaProjects\\test\\src\\main\\java\\cglib");
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserServiceImpl.class);//设置需继承的父类:被增强类
        enhancer.setCallback(new UserServiceCGLib());//设置拦截器:增强方法
        UserServiceImpl userService = (UserServiceImpl)enhancer.create();//获取代理对象
        userService.run();//执行方法:多态调用子类方法,代理类中传入MethodInterceptor的实现类,会调用实现类intercept方法
    }
}
class UserServiceCGLib implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("前置通知");
        Object invokeSuper = methodProxy.invokeSuper(o, objects);
        System.out.println("后置通知");
        return invokeSuper;
    }
}

总结

动态代理使用场景很多,如:打印日志,数据脱敏,耗时统计等等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值