动态代理


spring中的AOP就是利用JDK的动态代理来生成对象的,该对象可以作为目标对象使用
可是sping 中的AOP代理可以有JDK动态代理,也有CGLIB代理。

JDK 动态代理

  1. 首先创建UserDao,编写两个方法-添加和删除
package com.java.jdk;

/**
 * Created by IntelliJ IDEA.
 *
 * @version : 1.0
 * @auther : Firewine
 * @mail : 1451661318@qq.com
 * @Program Name: <br>
 * @Create : 2018-12-05-19:12
 * @Description :  <br/>
 */
public interface UserDao {
    public void addUser();
    public void deleteUser();
}
  1. 实现UserDao 的两个方法
package com.java.jdk;

/**
 * Created by IntelliJ IDEA.
 *
 * @version : 1.0
 * @auther : Firewine
 * @mail : 1451661318@qq.com
 * @Program Name: <br>
 * @Create : 2018-12-05-19:13
 * @Description :  <br/>
 */
public class UserDaoImpl implements UserDao{
    //是以这个类作为目标类,进行增强处理
    @Override
    public void addUser() {
        System.out.println("添加用户");
    }

    @Override
    public void deleteUser() {

        System.out.println("删除用户");
    }
}
  1. 模拟切面,加个两个权限和日志方法
package com.java.aspect;

/**
 * Created by IntelliJ IDEA.
 *
 * @version : 1.0
 * @auther : Firewine
 * @mail : 1451661318@qq.com
 * @Program Name: <br>
 * @Create : 2018-12-05-19:15
 * @Description :  <br/>
 */
public class MyAspect {

    //下面两个方法模拟切面
    /**
     * 模拟权限检查方法
     */
    public void check_Permissions(){
        System.out.println("权限检查");
    }
    /**
     * 模拟日志方法
     */
    public void log(){
        System.out.println("记录日志");
    }
}
  1. 实现JDK代理类,需要实现InvocationHandle
package com.java.proxy;
import com.java.aspect.MyAspect;
import com.java.jdk.UserDao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Created by IntelliJ IDEA.
 *
 * @version : 1.0
 * @auther : Firewine
 * @mail : 1451661318@qq.com
 * @Program Name: <br>
 * @Create : 2018-12-05-19:17
 * @Description :  <br/>
 */
public class JdkProxy implements InvocationHandler {

    //声明目标类接口
    private UserDao userDao;

    //创建代理方法
    public Object createProxy(UserDao userDao){
        this.userDao = userDao;
        //1. 类加载器
        ClassLoader classLoader = JdkProxy.class.getClassLoader();
        //2. 被代理对象实现的所有接口
        Class[] classes = userDao.getClass().getInterfaces();
        //3. 使用代理类,进行增强,返回的是代理后的对象
        return Proxy.newProxyInstance(classLoader,classes,this::invoke);
    }
    /**
     * 所有的动态代理类的方法调用,都会交由invoke方法去处理
     * @param proxy  就是被代理后的对象
     * @param method 是要执行的方法(反射)
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        /**
         * 第一个参数 : 当前类的类加载器
         * 第二个参数 : 是被代理对象实现的所有的接口
         * 第三个参数 : 代表代理类JdkProxy的本身
         */
        //声明切面
        MyAspect myAspect  = new MyAspect();
        //前增强
        myAspect.check_Permissions();
        //在目标类上调用方法,传入参数
        Object obj = method.invoke(userDao,args);
        //后增强
        myAspect.log();
        return obj;
    }
}
  1. 最后一个编写测试类
package com.java.test;
import com.java.jdk.UserDao;
import com.java.jdk.UserDaoImpl;
import com.java.proxy.JdkProxy;

/**
 * Created by IntelliJ IDEA.
 *
 * @version : 1.0
 * @auther : Firewine
 * @mail : 1451661318@qq.com
 * @Program Name: <br>
 * @Create : 2018-12-05-19:25
 * @Description :  <br/>
 */
public class JdkTest {

    public static void main(String[] args) {
        //创建代理对象
        JdkProxy jdkProxy = new JdkProxy()
        //创建目标对象
        UserDao userDao = new UserDaoImpl();
        //从代理对象获取增强后的目标对象
        UserDao userDao1 = (UserDao) jdkProxy.createProxy(userDao);
        userDao1.addUser();
        userDao1.deleteUser();
    }
}
  1. 结果显示
    在这里插入图片描述

CGLIB代理

CGLIB 是一个高性能开源的代码生成包,它采用非常底层的字节码结束,对指定的目标类生成一个子类,并对子类进行增强。
这个也已经被集成到spring的核心包中了

  1. 实现一个目标类
package com.cglib.jdk;

/**
 * Created by IntelliJ IDEA.
 *
 * @version : 1.0
 * @auther : Firewine
 * @mail : 1451661318@qq.com
 * @Program Name: <br>
 * @Create : 2018-12-05-19:30
 * @Description :  <br/>
 */
public class UserDao {
    public void addUser() {
        System.out.println("添加用户");
    }
    public void deleteUser() {
        System.out.println("删除用户");
    }
}
  1. 创建代理类,需要实现MethodInterceptor接口,并实现接口的intercept方法
package com.cglib.proxy;
import com.java.aspect.MyAspect;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
/**
 * Created by IntelliJ IDEA.
 *
 * @version : 1.0
 * @auther : Firewine
 * @mail : 1451661318@qq.com
 * @Program Name: <br>
 * @Create : 2018-12-05-19:36
 * @Description :  <br/>
 */
public class CglibProxy implements MethodInterceptor {

    public Object CreateProxy(Object object){
        //创建一个动态类对象
        Enhancer enhancer = new Enhancer();
        //确定需要增强的类,设置其父类
        enhancer.setSuperclass(object.getClass());
        //添加回调函数
        enhancer.setCallback( this);
        //返回创建的代理类
        return enhancer.create();
    }

    /**
     * proxy CGLIB 根据指定父类生成的代理对象
     * method 拦截的方法
     * args 拦截方法的参数数组
     * methodProxy 方法的代理对象,用于执行父类的方法
     * @param
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //创建切面类对象
        MyAspect myAspect = new MyAspect();
        myAspect.check_Permissions();
        Object object = methodProxy.invokeSuper(methodProxy,objects);
        myAspect.log();
        return object;
    }
}

  1. 创建测试类
package com.cglib.test;

import com.cglib.jdk.UserDao;
import com.cglib.proxy.CglibProxy;

/**
 * Created by IntelliJ IDEA.
 *
 * @version : 1.0
 * @auther : Firewine
 * @mail : 1451661318@qq.com
 * @Program Name: <br>
 * @Create : 2018-12-05-19:49
 * @Description :  <br/>
 */
public class CglibTest {
    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();
        UserDao userDao = new UserDao();
        UserDao userDao1 = (UserDao) cglibProxy.CreateProxy(userDao);
        userDao1.addUser();
        userDao1.deleteUser();
    }
}
  1. Enhancer 是CGLIB的核心类,然后调用该类的setSuperclass方法来确定目标对象,然后setCallback方法添加回调函数,
  2. 而且这两个代理的不同之处,就是JDK需要实现接口的但是只需要jdk。而CGLIB是不需要接口的,但是需要导入Spring的核心包。

转载于:https://www.cnblogs.com/YJBlog/p/10092213.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值