zoukankan      html  css  js  c++  java
  • Java核心篇,二十三种设计模式(一),结构型——代理模式

    一、代理模式

    1.何为代理模式

    一种java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等

    代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务

    简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途

    2.代理模式的优点

    • 优点一:可以隐藏真实目标类的实现;
    • 优点二:可以实现客户与真实目标类间的解耦,在不修改真实目标类代码的情况下能够做一些额外的处理

    二、静态代理

    1.定义

    由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成

    2.简单实现

    ①学生接口

    public interface IStudent {
        public abstract void giveMoney();
    }
    

    ②学生实现类

    public class StudentImpl implements IStudent{
    
        private String name;
    
        public StudentImpl(String name){
            this.name = name;
        }
    
    
        @Override
        public void giveMoney() {
            System.out.println(name + "同学上交了学费");
        }
    }
    

    ③学生代理类

    public class StudentProxy implements IStudent {
    
        private IStudent student;
    
        public StudentProxy(IStudent student){
            this.student = student;
        }
    
        @Override
        public void giveMoney() {
            //交学费以前可以做的事
            before();
            student.giveMoney();
            //交学费以后可以做的其他事
            after();
        }
    
        public void before(){
            System.out.println("班长替班主任向全班同学收取学费");
        }
    
        public void after(){
            System.out.println("班长将全班同学的学费交给了班主任");
        }
    }
    

    ④使用静态代理

    public class Realize {
    
        private static IStudent student;
        private static IStudent studentProxy;
    
        public static void main(String[] args) {
            student = new StudentImpl("小明");
            studentProxy = new StudentProxy(student);
            studentProxy.giveMoney();
        }
    }
    

    三、动态代理

    1.定义

    在程序运行时,运用反射机制动态创建而成,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码

    2.基于接口的动态代理

    (1)如何创建代理对象

    使用Proxy类中的newProxyInstance方法

    (2)创建代理对象的要求:

    被代理类最少实现一个接口,如果没有则不能使用

    (3)newProxyInstance方法的参数:

    ClassLoader: 类加载器

    它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器

    固定写法:

    [对象].getClass().getClassLoader()
    [类].class.getClassLoader()

    Class[]: 字节码数组

    它是用于让代理对象和被代理对象有相同方法

    固定写法:

    [对象].getClass().getInterfaces();
    [类].class.getInterfaces();

    InvocationHandler: 用于提供增强的代码

    它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类(不是必须的),此接口的实现类都是谁用谁写

    new InvocationHandler(){
                /**
                 * 执行被代理对象的任何方法都会经过invoke方法
                 * 方法参数的含义:
                 * proxy ===> 代理对象的引用
                 * method ===> 当前执行的方法
                 * args ===> 当前执行方法所需的参数
                 * return ===> 和被代理对象方法有相同的返回值
                 */
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    ......
                }
    };

    (4)代码实现(方法一:匿名内部类)

    ①学生接口

    public interface IStudent {
        public abstract void giveMoney();
    }
    

    ②接口实现类

    public class StudentImpl implements IStudent{
    
        private String name;
    
        public StudentImpl(String name){
            this.name = name;
        }
    
        @Override
        public void giveMoney() {
            System.out.println(name + "同学上交了学费");
        }
    }
    

    ③实现动态代理并执行

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class Realize {
    
        private static IStudent student;
    
        public static void before(){
            System.out.println("班长替班主任向全班同学收取学费");
        }
    
        public static void after(){
            System.out.println("班长将全班同学的学费交给了班主任");
        }
    
        public static void main(String[] args) {
            student = new StudentImpl("小明");
            IStudent iStudent = (IStudent) Proxy.newProxyInstance(student.getClass().getClassLoader(), student.getClass().getInterfaces(), new InvocationHandler() {
                /**
                 * 执行被代理对象的任何方法都会经过invoke方法
                 * 方法参数的含义:
                 * proxy ===> 代理对象的引用
                 * method ===> 当前执行的方法
                 * args ===> 当前执行方法所需的参数
                 * return ===> 和被代理对象方法有相同的返回值
                 */
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    before();
                    /**
                     * invoke方法的参数
                     * 第一个为被代理对象
                     * 第二个为方法参数-args
                     */
                    Object obj = method.invoke(student, args);
                    after();
                    return obj;
                }
            });
    
            iStudent.giveMoney();
        }
    }
    

    (5)代码实现(方法二:自定义类,实现动态代理接口)

    ①学生接口

    public interface IStudent {
        public abstract void giveMoney();
    }
    

    ②接口实现类

    public class StudentImpl implements IStudent{
    
        private String name;
    
        public StudentImpl(String name){
            this.name = name;
        }
    
        @Override
        public void giveMoney() {
            System.out.println(name + "同学上交了学费");
        }
    }
    

    ③动态代理接口的实现类

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class StudentProxy<T> implements InvocationHandler {
    
        private T target;
    
        public StudentProxy(T target){
            this.target = target;
        }
    
        public void before(){
            System.out.println("班长替班主任向全班同学收取学费");
        }
    
        public void after(){
            System.out.println("班长将全班同学的学费交给了班主任");
        }
    
        /**
         * 执行被代理对象的任何方法都会经过invoke方法
         * 方法参数的含义:
         * proxy ===> 代理对象的引用
         * method ===> 当前执行的方法
         * args ===> 当前执行方法所需的参数
         * return ===> 和被代理对象方法有相同的返回值
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            before();
            /**
             * invoke方法的参数
             * 第一个为被代理对象
             * 第二个为方法参数-args
             */
            Object obj = method.invoke(target, args);
            after();
            return obj;
        }
    }
    

    ④使用动态代理

    import java.lang.reflect.Proxy;
    
    public class Realize {
    
        private static IStudent student;
        private static StudentProxy studentProxy;
    
        public static void main(String[] args) {
            student = new StudentImpl("小明");
            studentProxy = new StudentProxy(student);
    
            /**
             * newProxyInstance方法的参数:
             * ClassLoader: 类加载器
             * 它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器
             * Class[]: 字节码数组
             * 它是用于让代理对象和被代理对象有相同方法
             * InvocationHandler: 用于提供增强的代码
             * 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类(不是必须的),此接口的实现类都是谁用谁写
             */
            IStudent iStudent = (IStudent) Proxy.newProxyInstance(student.getClass().getClassLoader(), student.getClass().getInterfaces(), studentProxy);
            iStudent.giveMoney();
        }
    }
    

    3.基于子类的动态代理

    1.确保项目是Maven工程

    2.在pom.xml中设置打包方式

    <packaging>jar</packaging>

    3.在pom.xml中导入依赖坐标

    <dependencies>
            <dependency>
                <groupId>cglib</groupId>
                <artifactId>cglib</artifactId>
                <version>2.1_3</version>
            </dependency>
    </dependencies>

    4.最终pom.xml为

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>org.example</groupId>
        <artifactId>demo19</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>jar</packaging>
    
        <dependencies>
            <dependency>
                <groupId>cglib</groupId>
                <artifactId>cglib</artifactId>
                <version>2.1_3</version>
            </dependency>
        </dependencies>
    
    
    </project>

    5.依赖与使用

    依赖类 ===> Enhancer

    使用方法 ===> Enhancer.create()

    6.要求

    被代理类不能是最终类

    7.参数

    Class ===> 用于指定被代理对象的字节码

    Callback ===> 用于提供增强的代码;我们一般写该接口的子接口实现类——>MethodInterceptor

    8.代码实现(方法一:匿名内部类)

    (1)学生接口

    public interface IStudent {
        public abstract void giveMoney();
    }
    

    (2)学生接口实现类

    public class StudentImpl implements IStudent{
    
        private String name;
    
        /**
         * 当实现CGLIB代理的时候,如果目标对象没有定义无参构造函数,当Enhancer对象create代理对象的时候,就会报错
         * 因为Spring通过CGLIB生成代理类对象时,并没有将目标对象的构造函数的参数及其类型进行设定,导致了CGLIB在生成代理类对象时,会使用默认的构造函数生成,结果目标对象类没有默认构造函数,CGLIB生成子类时,也没有加入默认构造函数,所以,异常的发生成为必然
         * 所以这里需要加入默认构造函数
         */
        public StudentImpl(){
            this.name = null;
        }
    
        public StudentImpl(String name){
            this.name = name;
        }
    
        @Override
        public void giveMoney() {
            System.out.println(name + "同学上交了学费");
        }
    }
    

    (3)动态代理的实现

    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 Realize {
    
        private static IStudent student;
    
        public static void before(){
            System.out.println("班长替班主任向全班同学收取学费");
        }
    
        public static void after(){
            System.out.println("班长将全班同学的学费交给了班主任");
        }
    
        public static void main(String[] args) {
    
            student = new StudentImpl("小明");
    
            /**
             * Class ===> 用于指定被代理对象的字节码
             * Callback ===> 用于提供增强的代码;我们一般写该接口的子接口实现类——>MethodInterceptor
             */
            IStudent iStudent = (IStudent) Enhancer.create(student.getClass(), new MethodInterceptor() {
                 /**
                  * 执行被代理对象的任何方法都会经过该方法
                  * o ===> 代理对象的引用
                  * method ===> 当前执行的方法
                  * objects ===> 当前执行方法所需的参数
                  * methodProxy ===> 当前执行方法的代理对象
                  * return ===> 和被代理对象方法有相同的返回值
                  */
                 @Override
                 public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                     before();
                     Object obj = method.invoke(student);
                     after();
                     return obj;
                 }
            });
    
             iStudent.giveMoney();
        }
    }
    

    9.代码实现(方法二:自定义接口实现类)

    (1).学生接口

    public interface IStudent {
        public abstract void giveMoney();
    }
    

    (2)学生接口实现类

    public class StudentImpl implements IStudent{
    
        private String name;
    
        /**
         * 当实现CGLIB代理的时候,如果目标对象没有定义无参构造函数,当Enhancer对象create代理对象的时候,就会报错
         * 因为Spring通过CGLIB生成代理类对象时,并没有将目标对象的构造函数的参数及其类型进行设定,导致了CGLIB在生成代理类对象时,会使用默认的构造函数生成,结果目标对象类没有默认构造函数,CGLIB生成子类时,也没有加入默认构造函数,所以,异常的发生成为必然
         * 所以这里需要加入默认构造函数
         */
        public StudentImpl(){
            this.name = null;
        }
    
        public StudentImpl(String name){
            this.name = name;
        }
    
        @Override
        public void giveMoney() {
            System.out.println(name + "同学上交了学费");
        }
    }
    

    (3)学生代理类

    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    import java.lang.reflect.Method;
    
    public class StudentProxy<T> implements MethodInterceptor {
    
        private T target;
    
        public StudentProxy(T target){
            this.target = target;
        }
    
        public void before(){
            System.out.println("班长替班主任向全班同学收取学费");
        }
    
        public void after(){
            System.out.println("班长将全班同学的学费交给了班主任");
        }
    
        /**
         * 执行被代理对象的任何方法都会经过 intercept方法
         * 方法参数的含义:
         * o ===> 代理对象的引用
         * method ===> 当前执行的方法
         * objects ===> 当前执行方法所需的参数
         * return ===> 和被代理对象方法有相同的返回值
         */
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            before();
            Object obj = method.invoke(target);
            after();
            return obj;
        }
    }
    

    (4)使用动态代理

    import net.sf.cglib.proxy.Enhancer;
    
    public class Realize {
    
        private static IStudent student;
        private static StudentProxy<IStudent> studentProxy;
    
        public static void main(String[] args) {
    
            student = new StudentImpl("小明");
            studentProxy = new StudentProxy<IStudent>(student);
    
            /**
             * Class ===> 用于指定被代理对象的字节码
             * Callback ===> 用于提供增强的代码;我们一般写该接口的子接口实现类——>MethodInterceptor
             */
            IStudent iStudent = (IStudent) Enhancer.create(student.getClass(), studentProxy);
            iStudent.giveMoney();
        }
    }
    
    作者:蓝月

    -------------------------------------------

    个性签名:能我之人何其多,戒骄戒躁,脚踏实地地走好每一步

  • 相关阅读:
    thinkphp url生成
    thinkphp url大小写
    thinkphp 伪静态
    thinkphp action参数绑定
    thinkphp 前置和后置操作
    thinkphp 控制器定义
    thingkphp 路由实例
    thinkphp 闭包支持
    thinkphp 静态路由
    thinkphp 正则路由
  • 原文地址:https://www.cnblogs.com/viplanyue/p/13573746.html
Copyright © 2011-2022 走看看