spring&代理入门笔记

上一篇-Spring&IOC入门笔记

第四章 代理

4.1 什么是代理

概念:代理就好比是买卖关系之间的中介,充当着中间人的角色,转达买卖双方的诉求,比如,买家说:你的商品不好,不值这个价钱,降低一点,或者多给一点。卖家说:我的商品好极了,没有任何瑕疵,错过了就没有,自然不肯降价。这时中间人(代理)就出来说话了,中间人对买家说,你把钱给我,把你的要求说出来,我给你办的妥妥的。然后在对卖家说,把你的商品给我,保证你的商品卖的稳稳地。就这样,问题就解决了。

结论

如果两者之间存在这直接关系,当需求改变时,容易引起另一个的不同意,从而无法满足需求,此时,中间人(代理)来缓和关系,并满足他们的需求。 把这个结论运用到代码当中,当需要对代码进行功能增强时,发现原来的代码不支持在原有的基础上进行添加。或者说,添加了会造成原有的代码结构混乱。所以,为了解决这个问题,提出了代理概念。

4.2 代理有几种模式

代理分为静态代理和动态代理。
静态代理 : 表示它的状态在编码时就已经决定了,在虚拟机编码阶段,就把它增强的代码编码到代理对象上。
动态代理: 它的状态在程序运行时动态的生成代理类,通过代理类去实现功能的增强,它的字节码文件由程序运行时通过反射机制生成。

4.3 静态代理的实现

4.3.1 基于接口实现静态代理

创建一个新的maven项目
定义一个接口UserDao ,有增删改查方法。

public interface UserDao {

    void save();
    void delete();
    void update();
    void find();
}

定义一个实现类实现UserDao接口,并实现所有方法

 class UserDaoImpl implements UserDao{

    @Override
    public void save() {
        System.out.println("UserDaoImpl saving...");
    }

    @Override
    public void delete() {
        System.out.println("UserDaoImpl deleting...");
    }

    @Override
    public void update() {
        System.out.println("UserDaoImpl updating...");
    }

    @Override
    public void find() {
        System.out.println("UserDaoImpl finding...");
    }
}

定义一个代理类对象,用于代理UserDao的实现类

package com.lyf.spring5.proxy;

public class StaticProxy {

    //定义接口属性,通过这个接口属性去调用代理对象的值
    private UserDao userDao;

    //通过有参构造接口赋值
    public StaticProxy(UserDao userDao){
        this.userDao = userDao;
    }

    /**
     * 增强的功能,添加记录日志功能
     */
    public void  log(){
        System.out.println("记录日志");
    }

    /**
     * 增强的检查权限功能
     */
    public void  check(){
        System.out.println("检查权限");
    }

    /**
     * 代理的方法实现功能增强
     */
    public void proxy(){
    	//this 表示当前对象调用自己的方法,可以省略不写
        this.check();// 表示删除前对权限进行校验,查看是否有权限执行删除方法
        userDao.delete();
        this.log();//表示删除方法执行完后就执行记录日志的方法

        check();
        userDao.find();
        log();
        check();
        userDao.save();
        log();
        check();
        userDao.update();
        log();
    }
}

定义一个主方法,测试静态代理

public class StaticMain {

    public static void main(String[] args) {
        // 创建一个实现了UserDao接口的UserDaoImpl实现类
        UserDao userDao = new UserDaoImpl();
        //创建代理类对象,并赋值给代理类
        StaticProxy staticProxy = new StaticProxy(userDao);
        //调用代理类方法
        staticProxy.proxy();
    }
}

运行结果

在这里插入图片描述

4.3.2 基于继承实现静态代理

编写一个类实现UserDaoImpl类。

package com.lyf.spring5.proxy;


public class ExtendUserDaoImpl extends UserDaoImpl {

    public static void main(String[] args) {
        ExtendUserDaoImpl proxy = new ExtendUserDaoImpl();
        proxy.proxy();
    }

    /**
     * 代理方法
     */
    public void proxy(){
        log();
        super.update();
        check();

        log();
        super.delete();
        check();

        log();
        super.find();
        check();

        log();
        super.save();
        check();
    }
    /**
     * 增强方法 记录日志
     */
    public void log(){
        System.out.println("记录日志");
    }

    /**
     * 增强方法 检查权限
     */
    public void check(){
        System.out.println("检查权限");
    }
}

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

总结:
静态代理通过硬编码的方式实现,如果需求不断的变更,会造成代码的冗余,代码结构混乱不清晰,造成难维护的局面。


4.4 动态代理的实现

概述:动态代理有两种实现方式,一种是基于JDK动态代理实现,另一种是基于CGLIB实现。

JDK代理:底层采用反射机制,通过java.lang.reflect.Proxy类来实现,调用Proxy类的newINstance方法创建代理对象。spring框架默认采用JDK动态代理。

CGLIB代理:开源的高性能的代码生成框架。生成的代理对象是基于目标对象的子类。

区别:JDK代理 是基于一个接口实现的,被代理的目标对象必须要有一个接口父类;CGLIB代理是基于继承实现的,生成的对象是继承该目标对象。


4.4.1 JDK动态代理代码实现

使用UserDao接口与实现类UserDaoImpl代理案例

因为实习InvocationHandler 类,所以在创建代理对象的参数当中直接传递了this

package com.lyf.spring5.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


public class DynamicProxy implements InvocationHandler {

    //被代理的对象,这里是接口,主函数传过来的实现是该接口的实现类,该接口的实现类才是被代理的对象。
    private  UserDao userDao;

    /**
     * 有参构造方法,给代理对象的属性userDao赋值
     * @param userDao
     */
    public DynamicProxy(UserDao userDao){
        this.userDao =userDao;
    }

    /**
     * 获取代理对象,通过反射类Proxy的静态方法newInstance创建代理对象
     * newInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)创建代理对象的方法参数介绍
     *ClassLoader loader: 通过类加载器来定义代理类
     *Class<?>[] interfaces: 代理类实现的接口列表
     *InvocationHandler h):调度方法调用的处理函数
     * @return 返回一个代理对象
     */
    public UserDao proxy(){
        UserDao result = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
                userDao.getClass().getInterfaces(), this);
        return  result;
    }

    /**
     * 该方法是实现代码的动态代理核心
     * @param proxy  表示代理类
     * @param method 代理类调用被代理类的方法
     * @param args  被代理类的方法参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            check();//调用增强的方法
            //被代理的对象,参数,返回方法执行的结果
        Object result = method.invoke(userDao, args);
            log();//调用增强的方法
        return result;//返回方法的返回值
    }

    /**
     * 增强的功能,添加记录日志功能
     */
    public void  log(){
        System.out.println("记录日志");
    }

    /**
     * 增强的检查权限功能
     */
    public void  check(){
        System.out.println("检查权限");
    }

    public static void main(String[] args) {

        // new 一个被代理对象
        UserDao userDao = new UserDaoImpl();
        //调用代DynamicProxy生成代理对象
        UserDao result = new DynamicProxy(userDao).proxy();
        //返回的代理对象调用被代理对象的方法
        result.update();
        String save = result.save();
        System.out.println(save);
        result.find();
        result.delete();
    }
}

反射类对象创建代理对象的方法参数


    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException

运行结果
在这里插入图片描述
简写形式

public class DynamicMain {

    public UserDao proxy(UserDao userDao){
       UserDao  userDao1= (UserDao) Proxy.newProxyInstance(UserDaoImpl.class.getClassLoader(),
                UserDaoImpl.class.getInterfaces(),
               (proxy, method, args) -> {
                   System.out.println("检查权限");
                   Object result = method.invoke(userDao, args);
                   System.out.println("记录日志");
                   return result;
               });
        return userDao1;
    }
    public static void main(String[] args) {
        UserDao userDao = new UserDaoImpl();
        UserDao proxy = new DynamicMain().proxy(userDao);
        proxy.find();
        proxy.update();
    }
}

4.4.2 CGLIB动态代理实现

引入CGLIB代理依赖

 <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>

CGLIb 实现了MethodInterceptor 接口,所以在Hnhancer.create()传人的this对象。

package com.lyf.spring5.proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;


public class CGLIb implements MethodInterceptor {


    //被代理的目标对象
    private UserDaoImpl userDao;

    /**
     * 有参构造,给被代理对象赋值
     * @param userDao
     */
    public CGLIb(UserDaoImpl userDao){
        this.userDao = userDao;
    }

    /**
     * 调用Enhancer类的create静态方法创建被代理对象的代理类。
     * 传人create方法中的参数,一个是被代理对象类型,一个是回调函数,该会函调函数被当前类继承,所以,直接传人当前对象即可。
     * @return
     */
    public UserDaoImpl createCGLIB(){
        return (UserDaoImpl) Enhancer.create(UserDaoImpl.class, this);
    }

    /**
     * 重写的MethodInterceptor
     * @param o 代理类对象本身
     * @param method 代理类执行的方法
     * @param objects  方法执行的参数
     * @param methodProxy 方法代理
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {


        /**
         * 第一种实现方式
         * 使用反射进行代理
         */
//        System.out.println("权限检查");
//        Object result = method.invoke(userDao, objects);
//        System.out.println("记录日志");
//        return result;

        /**
         * 第二种实现方式
         * methodProxy.invoke使用 目标对象进行代理
         */
//        System.out.println("权限检查");
//        Object result = methodProxy.invoke(userDao, objects);
//        System.out.println("记录日志");
//        return result;
//
        /**
         * 第三种实现方式
         * methodProxy.invokeSuper使用 目标对象进行代理
         */
        System.out.println("权限检查");
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("记录日志");
        return result;

    }

    public static void main(String[] args) {
        //创建被代理类对象
        UserDaoImpl userDao = new UserDaoImpl();
        //传人被代理对象
        CGLIb cglIb = new CGLIb(userDao);
        //创建代理对象
        UserDaoImpl result = cglIb.createCGLIB();
        //代理对象调用目标对象方法
        result.update();
    }
}

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

简写形式



public  class CGLIbProxy {
    public Object enhancer(Object obj){
     return Enhancer.create(UserDaoImpl.class, (MethodInterceptor) (o, method, args, methodProxy) -> {
            System.out.println("权限检查");
            Object result = methodProxy.invoke(obj, args);
            System.out.println("日志检查");
            return result;
        });
    }

    public static void main(String[] args) {
        UserDaoImpl userDao = new UserDaoImpl();
        UserDaoImpl result = (UserDaoImpl) new CGLIbProxy().enhancer(userDao);
        result.find();
        result.update();
        result.delete();
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值