设计模式之代理模式

##代理模式 提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。例如:你需要去报考驾校,虽然现在也支持自考了但是自考很麻烦,需要自己去预约训练场地、找教练等待,但是你可以有一个很好的选择,去报驾校,委托驾校帮忙处理那些事情,而驾校就充当了一个代理的作用。你无需关注其他,只需要关注科目一二三四考试即可。

代理模式主要有静态代理和动态代理方式:

- 静态代理是通过在代码中显式定义一个业务实现类一个代理,在代理类中对同名的业务方法进行包装,用户通过代理类调用被包装过的业务方法;

- JDK动态代理是通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法;

- CGlib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理

1.创建业务接口

package com.dtree.proxy;

/**
 * 〈一句话功能简述〉
 *  业务接口
 * @author 
 * @date 2019年03月28日 19:44
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public interface Welcomes {

    void login();
}

2.创建业务接口实现类

package com.dtree.proxy;

/**
 * 〈一句话功能简述〉
 *  业务实现类
 * @author forest
 * @date 2019年03月28日 19:44
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class UserWelcome implements Welcomes {
    @Override
    public void login() {
        System.out.println("欢迎回来");
    }
}

 

3.静态代理模式

/**
 * 〈一句话功能简述〉
 *  静态代理
 * @author forest
 * @date 2019年03月28日 19:45
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class StaticProxy implements Welcomes {

    private UserWelcome target;
    private String name;
    private String pwd;

    public StaticProxy(UserWelcome target, String name, String pwd) {
        this.target = target;
        this.name = name;
        this.pwd = pwd;
    }

    @Override
    public void login() {
        if (name.equals("admin") && pwd.equals("admin")) {
            System.out.println(name+"登陆成功");
            target.enter();
        } else {
            System.out.println("账号密码错误,登陆失败");
        }
    }
}

3.1静态代理测试类

package com.dtree.proxy;

import static org.testng.Assert.*;

/**
 * 〈一句话功能简述〉
 *  简单的静态代理的demo测试;
 * @author forest
 * @date 2019年03月28日 19:47
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class StaticProxyTest {

//    静态代理模式总结:
//
//    优点:在没有对目标对象进行侵入式修改的前提下,对用户的登陆进行了参数校验,也是对目标对象功能的扩展和拦截。
//
//    缺点:代理对象必须与目标对象实现同一个接口,这样会产生多个不同的代理类,不易维护,并且当接口增加方法,代理和目标对象都需要进行统一维护。
    public static void main(String[] args) {
        Welcomes welcome = new StaticProxy(new UserWelcome(), "admin", "admin");
        welcome.login();
    }

}

4.JDK动态代理

package com.dtree.proxy;

import org.omg.CORBA.PUBLIC_MEMBER;

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

/**
 * 〈一句话功能简述〉
 * JDK动态代理
 *
 * @author forest
 * @date 2019年03月28日 17:31
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class DynamicProxy implements InvocationHandler {

    /**
     * 这其实业务实现类对象,用来调用具体的业务方法
     */
    private Object target;

    public Object bind(Object target) {
        this.target = target;//接收业务实现类对象参数
        //通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用
        //创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,
        // 在包装方法是调用真正的业务方法)、接口、handler实现类
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);

    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        System.out.println("开始操作------");

        //调用真正的业务方法
        result = method.invoke(target, args);

        System.out.println("结束后处理------");
        return result;
    }
}

4.1JDK动态代理测试类

package com.dtree.proxy;

import org.testng.annotations.Test;

import static org.testng.Assert.*;

/**
 * 〈一句话功能简述〉
 *  JDK动态代理
 * @author forest
 * @date 2019年03月28日 20:01
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class DynamicProxyTest {

    @Test
    public void functionDynamic() {

        //1.实例化业务类
        UserWelcome userWelcome = new UserWelcome();
        //2.创建JDK代理类
        DynamicProxy dynamicProxy = new DynamicProxy();
        //3.将业务类绑定到代理类,针对接口
        Welcomes bind = (Welcomes)dynamicProxy.bind(userWelcome);
        //4.即可实现无侵入的执行业务类
        bind.login();

    }
}

5.Cglib动态代理

package com.dtree.proxy;

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

import java.lang.reflect.Method;

/**
 * 〈一句话功能简述〉
 *   cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,
 *   并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。
 * @author forest
 * @date 2019年03月28日 20:19
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class CGlibProxy implements MethodInterceptor {

    private Object target;//业务类对象,供代理方法中进行真正的业务方法调用 //相当于JDK动态代理中的绑定

    public Object getInstance(Object target) {
        this.target = target;  //给业务对象赋值
        Enhancer enhancer = new Enhancer(); //创建加强器,用来创建动态代理类
        enhancer.setSuperclass(this.target.getClass());
        // 为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
        //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
        enhancer.setCallback(this);
        // 创建动态代理类对象并返回
        return enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("cglib代理开始处理——————");
        proxy.invokeSuper(obj, args); //调用业务类(父类中)的方法
        System.out.println("cglib调用后处理——————");
        return null;
    }
}

5.1Cglib代理测试类

package com.dtree.proxy;

import org.testng.annotations.Test;

import static org.testng.Assert.*;

/**
 * 〈一句话功能简述〉
 *
 * @author forest
 * @date 2019年03月28日 20:21
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class CGlibProxyTest {


    @Test
    public void functionDynamic() {

        //1.实例化业务类
        UserWelcome userWelcome = new UserWelcome();
        //2.创建CGLIB代理类
        CGlibProxy cGlibProxy = new CGlibProxy();
        //3.将业务类绑定到代理类
//        Welcomes bind = (Welcomes)cGlibProxy.getInstance(userWelcome);
        UserWelcome bind = (UserWelcome)cGlibProxy.getInstance(userWelcome);
        //4.即可实现无侵入的执行业务类
        bind.login();

    }

}

6.spring代理源代码:

如下:

  1. 如果目标对象实现了接口,默认情况下会采用JDK动态代理实现AOP
  2. 如果目标对象实现了接口,可以强制使用CGLIB实现AOP
  3. 如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换,而如何强制使用CGLIB实现AOP呢?在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>,默认false为jdk

package org.springframework.aop.framework;

import java.io.Serializable;
import java.lang.reflect.Proxy;
import org.springframework.aop.SpringProxy;
//spring默认代理类,实现了AopProxyFactory代理工厂
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
    public DefaultAopProxyFactory() {
    }

    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
            return new JdkDynamicAopProxy(config);
        } else {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation.");
            } else {
                return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
            }
        }
    }

    private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
        Class<?>[] ifcs = config.getProxiedInterfaces();
        return ifcs.length == 0 || ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值