JDK动态代理和CGLIB生成代理

一,JDK动态代理

       适用范围:只能对实现了接口的类进行动态代理

1,1:新建一个接口UserDao,新建实现类UserDaoImpl

        

import com.imooc.dao.UserDao;

/**
 * @author :PanXiuWen
 * @date :Created in 2019/12/16 10:36
 * @desc:UserDao的实现类UserDaoImpl 
 */
public class UserDaoImpl implements UserDao {
    public void save(String username,String password)
    {
        System.out.println("save success + "+username);
    }

    public void delete() {
        System.out.println("delete success");
    }

    public void update() {
        System.out.println("update success");
    }

    public void find() {
        System.out.println("find success");
    }
}

 1.2  JDK动态代理代码

import com.imooc.dao.UserDao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * @author :PanXiuWen
 * @date :Created in 2019/12/16 10:45
 */
public class MyJdkProxy {
    /**
     *
     * @param userDao 待增强的类(UserDao接口的实现类,UserDaoImpl)。这里为啥不直接传UserDaoImpl,而是传它的父类UserDao-->多态。
     *                  传UserDao时,可以确保传递它的所有子类也都可以。
     *                  如果传UserDaoImpl,那就只能增强UserDaoImpl里面的方法。
     * @return  增强后,产生的代理对象proxy
     * @desc:   动态代理,是对接口UserDao的具体实现类,他们中的某些方法进行增强。然后产生一个新的对象,即代理对象proxy
     */
    public Object createProxy(final UserDao userDao){
        /**
         * userDao.getClass().getClassLoader():类加载器
         * userDao.getClass().getInterfaces():待增强的类(UserDao接口的实现类,UserDaoImpl),它的实现类
         * new InvocationHandler(){..invoke..}:对待增强的类(UserDao接口的实现类,UserDaoImpl)中的某些方法,具体要做什么样子的增强。
         */
        Object proxy = Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
                userDao.getClass().getInterfaces(),
                new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if ("save".equals(method.getName())){
                    System.out.println("权限校验。。。");
                    if (args[0]=="root"&&args[1]=="password"){
                        System.out.println("权限校验通过");
                    }else{
                        System.out.println("权限校验不通过");
                    }
                    //执行父类userDao的方法
                    return method.invoke(userDao,args);
                }
                //如果不是save方法,就原封不动的去执行,不需要增强产生proxy对象
                return method.invoke(userDao,args);
            }
        });
        return proxy;
    }
}

1.3  使用JDK动态代理  

/**
     * JDK动态代理
     */
    @Test
    public void test1(){
        UserDao userDao = new UserDaoImpl();
        MyJdkProxy2 proxy = new MyJdkProxy2();
        UserDao proxyUserDao = (UserDao) proxy.createProxy(userDao);
//        userDao.save();
//        userDao.delete();
//        userDao.update();
//        userDao.find();
        proxyUserDao.save("root","password");
        proxyUserDao.delete();
        proxyUserDao.update();
        proxyUserDao.find();
    }

 二,CGLIB生成代理

        可以去生成一个类,去继承目标类(即针对目标类生成一个它的子类)。因此这种方式可以不用目标类实现了接口。
        引入spring的核心jar包,之后就可以使用CGLIB了。
            spring-beans spring-core spring-expression spring-context

2.1  创建一个类ProductUser 

/**
 * @author :PanXiuWen
 * @date :Created in 2019/12/16 11:27
 */
public class ProductUser {
    public void save(){
        System.out.println("save....");
    }
    public void delete(){
        System.out.println("delete....");
    }
    public void update(){
        System.out.println("update....");
    }
    public void find(){
        System.out.println("find....");
    }
}

 2.2  CGLIB生成代理

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

import java.lang.reflect.Method;

/**
 * @author :PanXiuWen
 * @date :Created in 2019/12/16 11:31
 */
public class MyCglibProxy {

    public Object createProxy(final ProductUser productUser){
        //1,创建核心类
        Enhancer enhancer = new Enhancer();
        //2,设置父类(为ProductUser生成一个子类)
        enhancer.setSuperclass(productUser.getClass());
        //3,设置回调
        enhancer.setCallback(new MethodInterceptor() {
            /**
             *
             * @param proxy
             * @param method 子类的方法 对象 [CGLIB生成的类]
             * @param args   方法参数
             * @param methodProxy  父类的方法 对象 []
             * @return
             * @throws Throwable
             */
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                if ("save".equals(method.getName())){
                    System.out.println("权限校验...");
                    return methodProxy.invokeSuper(proxy,args);
                }
                //执行父类的方法
                return methodProxy.invokeSuper(proxy,args);
            }
        });
        //4,生成代理
        Object proxy = enhancer.create();
        return proxy;
    }
}

2.3 使用 CGLIB代理

    /**
     * CGLIB生成代理
     */
    @Test
    public void test2(){
        ProductUser user = new ProductUser();
        MyCglibProxy myCglibProxy = new MyCglibProxy();
        ProductUser cglibProxyUser = (ProductUser)myCglibProxy.createProxy(user);
//        user.save();
//        user.delete();
//        user.update();
//        user.find();
        cglibProxyUser.save();

    }

 

代理知识总结:
1、Spring在运行期,生成动态代理对象,不需要特殊的编译器


2、Spring AOP的底层就是通过JDK动态代理或CGLib动态代理技术为目标Bean执行横向织入


1.若目标对象实现了若干接口,Spring使用JDK的java.lang.reflect.Proxy类代理。


2.若目标对象没有实现任何接口,Spring使用CGLIB库生成目标对象的子类


3、程序中应优先对接口创建代理,便于程序解耦维护


4、标记为final的方法,不能被代理,因为无法进行覆盖


    -JDK动态代理,是针对接口生成子类,接口中方法不能使用final修饰


    -CGLib是针对目标类生成子类,因此类或方法不能使用final的


5、Spring只支持方法连接点,不支持属性连接点

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值