静态代理、Jdk动态代理、Cglib动态代理、两种代理当目标类中有final和static和内部类的情况

参考:https://blog.csdn.net/qq_46158352/article/details/130616198

一.静态代理:(不通用)

一个代理类只代理一个对象(因为静态代理类写的时候就是实现被代理类对象的接口,不同接口就要写不同的代理类)
被代理对象一定要实现接口

public class StaticProxyExample {
    static class UserDaoImpl implements UserDao {
        @Override
        public void add() {
            System.out.println("添加功能");
        }

        @Override
        public void delete() {
            System.out.println("删除功能");
        }

    }
    //静态代理类
    static class StaticProxy implements UserDao {
        //要代理的对象
        UserDaoImpl userDaoImpl;

        public StaticProxy(UserDaoImpl userDaoImpl) {
            this.userDaoImpl = userDaoImpl;
        }

        public void add() {
            System.out.println("before");
            userDaoImpl.add();
            System.out.println("after");
        }
        public void delete() {
            System.out.println("before");
            userDaoImpl.delete();
            System.out.println("after");
        }
    }

    public static void main(String[] args) {
        //相当于是通过静态代理类去调用被代理类的方法(一个静态代理类只能代理1个类)
       UserDao staticProxyUserDao =  new StaticProxy(new UserDaoImpl());
       staticProxyUserDao.add();
       staticProxyUserDao.delete();
    }
}


before
添加功能
after
before
删除功能
after

二.Jdk动态代理:(通用,实现接口的类)

1.JDK动态代理不会像静态代理那样一个代理类只代理一个对象;而是形成一个模板,只要传入要被代理的对象,即可代理(代理类实现接口的方法,是反射去获取接口,然后去实现)
2.被代理对象一定要实现接口(因为Proxy类的构造方法入参:被代理对象的类加载器、被代理对象实现的接口、实现了InvocationHandler的类对象)

Proxy.newProxyInstance()方法创建了代理对象,并将方法调用委托给了JdkProxy。

//Jdk动态代理
public class JdkDynamicProxyExample {
    //Jdk动态代理:要求被代理类要实现接口的形式
    //因为Jdk动态代理,生成代理时需要传入被代理类的实现的所有接口:newProxyInstance(ud2.getClass().getClassLoader(), ud2.getClass().getInterfaces(), handler)
    static class UserDaoImpl implements UserDao {
        @Override
        public void add() {
            System.out.println("添加功能");
        }

        @Override
        public void delete() {
            System.out.println("删除功能");
        }

    }

    static class JdkProxy implements InvocationHandler {//调用处理器
        private Object target;

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

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("before");
            //Method对象的invoke方法入参:目标对象,和目标对象方法的入参
            Object result = method.invoke(target, args);
            System.out.println("after");
            return result;
        }
    }

    public static void main(String[] args) throws Exception {
        相当于是通过Jdk动态代理类去调用被代理类的方法(一个jdk动态代理类可以代理多个类)
        //Proxy.newProxyInstance():内部用反射,去构建一个代理类,拥有和传入接口一样的方法,方法内部调用的JdkProxy的invoke()方法。invoke()方法拓展了功能
        //Spring AOP就是这样的,相当于Jdk动态代理类代理了切面类和目标类,在invoke()方法里面调目标类的方法前和后先调切面类的方法
        UserDaoImpl userDaoImpl2 = new UserDaoImpl();
        JdkProxy jdkProxy = new JdkProxy(userDaoImpl2);
        //Proxy类的构造器newProxyInstance()的入参为:userDaoImpl2的类加载器、userDaoImpl2实现的接口和实现了InvocationHandler的类JdkProxy
        UserDao proxyUserDao = (UserDao) Proxy.newProxyInstance(userDaoImpl2.getClass().getClassLoader(), userDaoImpl2.getClass().getInterfaces(), jdkProxy);
        proxyUserDao.add();
        proxyUserDao.delete();
    }
}


before
添加功能
after

before
删除功能
after


三.Cglib动态代理:(通用,普通类都可)

1.CGLIB动态代理不要求被代理的类实现接口
2.实现原理是在运行时动态生成被代理类的子类:并重写

Enhancer类创建了代理对象,并将方法调用委托给了CglibProxy

public class CglibDynamicProxyExample {
    //Cglib动态代理,不要求被代理类要实现接口的形式
    //因为Cglib,生成代理时,将目标类设置为父类的形式生成的代理
    static class UserDaoImpl {

        public void add() {
            System.out.println("添加功能");
        }


        public void delete() {
            System.out.println("删除功能");
        }

    }

    static class CglibProxy implements MethodInterceptor {//方法拦截器
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("before");
            Object result = proxy.invokeSuper(obj, args);
            System.out.println("after");
            return result;
        }
    }

    public static void main(String[] args) {
        UserDaoImpl userDaoImpl = new UserDaoImpl();
        Enhancer enhancer = new Enhancer();  //翻译 Enhancer:加强器
        // 此处将目标类设置为父类,生成该类的子类来实现动态代理,所以如果此时将Hello类声明为final,则会报IllegalArgumentException;但不要求实现接口
        enhancer.setSuperclass(UserDaoImpl.class);
        enhancer.setCallback(new CglibProxy());

        UserDaoImpl userDaoImplProxy = (UserDaoImpl) enhancer.create();
        //相当于是通过Cglib动态代理类去调用被代理类的方法(一个Cglib动态代理类可以代理多个类)
        userDaoImplProxy.add();
        userDaoImplProxy.delete();
    }
}


before
添加功能
after
before
删除功能
after

四.两种代理当目标类中有final和static和内部类的情况

1.Jdk动态代理 :只会代理接口中的非static方法,方法如果调用了其他方法,其他方法不会被代理

(1):目标类实现的接口中不可能有final修饰的方法,所以不能代理

public interface testInterface {
    //报错,Modifier 'final' not allowed here,接口中不允许定义final的方法
    //public final set();
}

(2):目标类实现的接口中有static修饰的方法,因为static修饰的方法不能重写,所以不能代理

Java 8开始,接口当中允许定义静态方法。格式:
public static 返回值类型方法名称(参数列表){
        方法体

}

(3)目标类中的内部类:Jdk动态代理是根据目标类的接口来生成代理类的,所以代理不了

2.Cglib动态代理

(1):目标类中有final修饰的方法,因为final修饰的方法可以被继承,但是不能重写,所以不能代理
(2):目标类中有static修饰的方法,因为static修饰的方法可以被继承,但是不能重写,所以不能代理
(3):目标类中的内部类:

代理目标对象不能是内部类(因为内部类的创建依赖外部类),如果是内部类,cglib代理内部会获取到一个有参构造函数(参数是外部类对象,如果实在需要代理一个内部类,可以通过传递构造参数实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值