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);
}
}