10.SSM框架集~代理模式

10.SSM框架集~代理模式

本文是上一篇文章的后续,详情点击该链接

代理模式的概念

       代理模式是Java常见的设计模式之一。所谓代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。 为什么要采用这种间接的形式来调用对象呢?一般是因为客户端不想直接访问实际的对象,或者访问实际的对象存在困难,因此通过一个代理对象来完成间接的访问。

代理模式的分类:

       1.静态代理

       2.动态代理[JDK动态代理,CGLIB动态代理]

代理模式的角色

       抽象的类或者接口--定义完成一件怎样的事情

       代理对象---完成这件事情的对象,直接面向用户的

       被代理对象--完成事件背后的隐藏内容,用户看不到

代理模式案例

       完成计算器案例,实现加减乘除操作

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>com.alvin</groupId>
    <artifactId>CodeSystem</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

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

    </dependencies>

</project>

在这里插入图片描述

Calculator接口

//定义接口
public interface Calculator{
    //加法
    Double add(Double num1, Double num2);
    //减法
    Double subtraction(Double num1, Double num2);
    //乘法
    Double multiplication(Double num1, Double num2);
    //除法
    Double division(Double num1, Double num2);
}

CalculatorImpl实现类

//实现接口
public class CalculatorImpl implements Calculator{

    public Double add(Double num1, Double num2) {
        Log4j.log("add",num1,num2);
        Double result = num1 + num2;
        return result;
    }

    public Double subtraction(Double num1, Double num2) {
        Log4j.log("subtraction",num1,num2);
        Double result = num1 - num2;
        return result;
    }

    public Double multiplication(Double num1, Double num2) {
        Log4j.log("multiplication",num1,num2);
        Double result = num1 * num2;
        return result;
    }

    public Double division(Double num1, Double num2) {
        Log4j.log("division",num1,num2);
        Double result = num1 / num2;
        return result;
    }
}

Log4j

//日志功能
public class Log4j {
    public  static void log(String  method,Double num1,Double num2){
        System.out.println("当前执行的方法为" + method  + ", 参数一:" + num1+ ", 参数二:" + num2);
    }
}

测试

public class MyCalculator {
    public static void main(String[] args) {
        Calculator calculator = new CalculatorImpl();
        double result = calculator.add(7.0,9.0);
        System.out.println(result);
    }
}

在这里插入图片描述

       但其实我们发现这样写会有一个弊端,那就是每当写一个方法,都要在方法里面改参数,那么假如我们要写五百个方法,就也要改五百次嘛?那么,我们就来试试更好的方案!

JDK动态代理

动态代理简介

       动态代理有别于静态代理,是根据代理的对象,动态创建代理类。这样,就可以避免静态代理中代理类接口过多的问题。动态代理是实现方式,是通过反射来实现的,借助Java自带的java.lang.reflect.Proxy,通过固定的规则生成

在这里插入图片描述

CalculatorImpl稍微改变
class CalculatorImpl implements Calculator {

    public Double add(Double num1, Double num2) {
        Double result = num1 + num2;
        return result;
    }

    public Double subtraction(Double num1, Double num2) {
        Double result = num1 - num2;
        return result;
    }

    public Double multiplication(Double num1, Double num2) {
        Double result = num1 * num2;
        return result;
    }

    public Double division(Double num1, Double num2) {
        Double result = num1 / num2;
        return result;
    }
}
JDKProxy
public class JDKProxy  {
    public static Object  getInstance(final Object  object){

        return Proxy.newProxyInstance(object.getClass().getClassLoader(), new Class[]{Calculator.class}, new InvocationHandler() {

            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //记录日志功能阔赞实现
                Log4j.log(method.getName(),args[0],args[1]);
                //执行目标方法内容
                Object invoke = method.invoke(object, args);
                return invoke;
            }
        });
    }
}
测试
public class MyCalculator {
    public static void main(String[] args) {
        //返回的就是代理对象
        Calculator instance =(Calculator) JDKProxy.getInstance(new CalculatorImpl());
        //调用代理对象中Add方法
        Double add = instance.add(7.0, 5.0);
        //输出结果
        System.out.println(add);
    }
}

在这里插入图片描述

       这个时候会发现,无论写多少个方法,都无需修改代码

CGLIB动态代理

JDK动态代理存在的问题

       JDK代理的产生必须要实现对应的接口的,如果没有对应的接口,这个时候代理对象就没有办法产生。

解决的方案

       CGLIB动态代理

CGLIB代理

       cglib的原理是这样,它生成一个继承B的类型C(代理类),这个代理类持有一个MethodInterceptor,我们setCallback时传入的。 C重写所有B中的方法(方法名一致),然后在C中,构建名叫“CGLIB”+“$父类方法名$”的方法(下面叫cglib方法,所有非private的方法都会被构建),方法体里只有一句话super.方法名(),可以简单的认为保持了对父类方法的一个引用,方便调用。

       这样的话,C中就有了重写方法、cglib方法、父类方法(不可见),还有一个统一的拦截方法(增强方法intercept)。其中重写方法和cglib方法肯定是有映射关系的。

代码实现

在这里插入图片描述

先在pom.xml里面导入依赖

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>
CGLIBProxy类
public class CGLIBProxy {
    public static Object getProxy(final Object object){
        Enhancer enhancer = new Enhancer();
        //设置代理对象的父类
        enhancer.setSuperclass(object.getClass());
        //设置回调函数
        enhancer.setCallback(new MethodInterceptor() {
            //提供给用户进行方法增强的代码
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                //代码增强A
                System.out.println("代码扩展AAAA");
                //反射执行目标对象
                Object invoke = method.invoke(object, objects);
                //执行目标对象
                System.out.println("代码扩展BBB");
                return invoke;
            }
        });
        //使整个操作生效
        Object o = enhancer.create();
        return o;
    }
}
CalculatorImpl2
public class CalculatorImpl2 {

    public Double add(Double num1, Double num2) {
        Double result = num1 + num2;
        return result;
    }

    public Double subtraction(Double num1, Double num2) {
        Double result = num1 - num2;
        return result;
    }

    public Double multiplication(Double num1, Double num2) {
        Double result = num1 * num2;
        return result;
    }

    public Double division(Double num1, Double num2) {
        Double result = num1 / num2;
        return result;
    }
}
main
public class MyCalculator {
    @Test
    public static void main(String[] args) {
        //返回的是动态产生的代理对象
        CalculatorImpl2 proxy = (CalculatorImpl2) CGLIBProxy.getProxy(new CalculatorImpl2());
        //调用代理对象方法
        Double result = proxy.add(7.9, 8.0);

    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章