Spring的设计模式
设计模式
动态代理
JDK动态代理
- Proxy:获得代理对象
代理对象 extends Proxy implement 目标类接口
// 返回代理对象
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h);
// 通过执行对象调用目标对象的方法,增强的逻辑是写InvocationHandler的实例在invoke()
//loader:目标类的类加载器,代码生成后,编译,重新动态load.class到JVM;
//interfaces:目标类的所有接口,获得代理的方法;
//h:实现InvocationHandler接口类的实例,重写invoke,执行者
-
原理流程
1、生成源代码.java,与目标对象实现相同的接口
2、将生成的源代码.java文件
3、编译源代码,并且生成.Class文件
4、将class文件中的内容,动态加载JVM中来
5、返回被代理后的代理对象
6、所有通过代理对象调用方法,实际就是执行者的invoke() -
code
/**
* 目标类接口
*
* @author xw
* @date 2019/9/23 23:55
*/
public interface Person {
void getName();
}
/**
* 目标被代理类
*
* @author xw
* @date 2019/9/23 23:56
*/
public class Guojiang implements Person {
@Override
public void getName() {
System.out.println("姓名:锅酱~");
System.out.println("锅酱,在找女朋友~");
}
}
/**
* 媒婆执行增强类
*
* @author xw
* @date 2019/9/24 11:13
*/
public class MeiPo implements InvocationHandler {
//目标对象引用
private Person target;
public Object getProxy(Person target) {
this.target = target;
Class clazz = target.getClass();
/**
* 为了获得目标对象的信息
* clazz.getClassLoader():目标对象的类加载器
* clazz.getInterfaces():目标对象的接口数组
* this:实现InvocationHandler接口实例
*/
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}
/**
* 所有代理对象执行接口方法都会被拦截,逻辑增强也是在此
* 媒婆类就是执行者,JDK生成的代理对象,实际调用执行者来增强逻辑
*
* @param proxy 代理对象的引用
* @param method 方法对象
* @param args 方法参数
* @return 方法的返回值
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 执行者调用目标对象的方法
method.invoke(target, args);
System.out.println("增强逻辑.....");
return null;
}
}
CGLib动态代理
-
MethodInterceptor 方法拦截接口
-
code
/**
* 目标学生类
*
* @author xw
* @date 2019/9/24 14:02
*/
public class Student {
public void study() {
System.out.println("学习~~~");
}
}
/**
* 执行类
*
* @author xw
* @date 2019/9/24 14:02
*/
public class ProxyStudent implements MethodInterceptor {
/**
* 获得代理对象
*
* @param clazz 目标对象
* @return
*/
public Object getInstance(Class clazz) {
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(clazz);
//回调
enhancer.setCallback(this);
/**
* 创建代理对象
* 1.生成源代码
* 2.编译class文件
* 3.加载进JVM,并返回代理对象
*/
return enhancer.create();
}
/**
* 方法拦截,增强
*
* @param obj 目标对象引用
* @param method 执行的方法对象
* @param args 方法参数
* @param proxy 代理对象引用
* @return 方法的返回值
* @throws Throwable
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
//调用父类的方法
//这个obi的引用是由CGLib给我们new出来的
//cglib new出来的对象,是被代理对象的子类(子父类关系)
//00P,在new子类之前,实际上默认先调用了我们super()方法的,
//new了子类的同时,必须先new出来父类,这就相当于是间接的持有了我们父类的引用
//子类重写了父类的所有的方法
//当改变子类对象的某些属性,是可以间接的操作父类的属性的
proxy.invokeSuper(obj, args);
System.out.println("CGLib增强逻辑,请代练学习....");
return null;
}
}
总结
动态代理本质是字节码重组
- JDK动态代理与CGLib动态代理区别
- JDK的动态代理是基于接口的,通过接口进行强制转换的生成以后的代理对象。[代理对象 extends Proxy implement 目标类接口]
- CGLib的动态代理基于继承子父类关系,通过生成一个被代理对象的子类,然后重写父类的方法,生成的对象,可以强制转换为被代理对象(也就是用自己写的类),子类引用赋值给父类。
工厂模式
隐藏复杂的逻辑处理过程,只关心执行结果。
简单工厂
- 特点
只需给定指定条件,工厂包含必要逻辑判断,依据条件实例化所需产品
在用到简单工厂的情况下,可以考虑反射去除switch或if分钟的耦合 - 缺点
代码逻辑判断紊乱,维护困难耦合高,拓展不灵活 - code
/**
* @author xw
* @date 2019/8/2 22:06
* 计算器最顶层接口
*/
public interface Operation {
public Double getResult(Double a, Double b);
}
/**
* @author xw
* @date 2019/8/2 22:23
* 运算工厂类
*/
public class OperationFactory {
/**
* 简单工厂
* @param str 运算符
* @return
*/
public static Operation creatOper(String str) {
Operation oper =null;
switch (str) {
case "+":
oper = new AddOperation();
return oper;
case "-":
oper = new SubOperartion();
return oper;
case "/":
oper = new DivisionOperartion();
return oper;
default:
return oper;
}
}
}
工厂方法
/**
* 工厂方法
*
* @author xw
* @date 2019/9/24 16:01
*/
public class BMWFactory {
//通常是静态方法
public Car getCar() {
System.out.println("BMW工厂生产汽车");
return new Car("BWM");
}
}
抽象工厂
- 抽象工厂包含所有产品的创建的抽象方法,由具体工厂去实现产品,由客户端决定使用哪个工厂。
/**
* 抽象工厂
*
* @author xw
* @date 2019/9/24 15:46
*/
public abstract class AbstractFactory {
abstract Car getCar();
public Car getCar(String name) {
if ("BMW".equalsIgnoreCase(name)) {
return new BMWFactory().getCar();
} else if (name == null) {
System.out.println("无工厂生产");
return null;
}
return null;
}
}
/**
* 具体工厂实现
*
* @author xw
* @date 2019/9/24 16:01
*/
public class BMWFactory extends AbstractFactory {
public Car getCar() {
System.out.println("BMW工厂生产汽车");
return new Car("BWM");
}
}
/**
* 默认工厂
*
* @author xw
* @date 2019/9/24 16:05
*/
public class DefaultFactory extends AbstractFactory {
//默认工厂
private BMWFactory factory = new BMWFactory();
@Override
Car getCar() {
System.out.println("默认工厂创建对象");
return factory.getCar();
}
}
//客户端调用
public static void main(String[] args) {
DefaultFactory fatory = new DefaultFactory();
//默认工厂生产
fatory.getCar();
System.out.println("**********");
//指定工厂生产产品
fatory.getCar("BMW");
}
单例模式
-
特点
1、保证从系统启动到系统终止,全过程只会产生一个实例。
2、当我们在应用中遇到功能性冲突(例如配置文件)的时候,需要使用单例模式。 -
JVM加载类的顺序
- 从上到下(声明前,使用后)
- 先属性(成员),后方法
- 先静态,后非静态
- 先父类,后子类
父类的静态字段——>父类静态代码块——>子类静态字段——>子类静态代码块——>
父类成员变量(非静态字段)——>父类非静态代码块——>父类构造器——>子类成员变量——>子类非静态代码块——>子类构造器
- code
//懒汉式(静态内部类)
//即解决安全问题,又解决了性能问题
public class Singleton4 {
//1、先声明一个静态内部类
//private 私有的保证别人不能修改
//static 保证全局唯一
private static class LazyHolder {
//final为了防止内部误操作
private static final Singleton4 INSTANCE = new Singleton4();
//2、将默认构造方法私有化
private Singleton4() {
}
//3、同样提供静态方法获取实例//final 确保别人不能覆盖
public static final Singleton4 getInstance() {
return LazyHolder.INSTANCE;
}
}
}
委派模式
- 特点
1、类似于中介的功能(委托机制,受托人,委托人);
2、持有被委托人的引用。
3、不关系过程,只关心结果 - 目的
隐藏具体实现逻辑
保证结果的多样性,对于外暴露只有一种方法 - code
/**
* 执行的事
*
* @author xw
* @date 2019/9/24 16:59
*/
public interface IExector {
void doSomething();
}
/**
* 具体执行者
*
* @author xw
* @date 2019/9/24 16:59
*/
public class ExectorA implements IExector {
@Override
public void doSomething() {
System.out.println("开始干活...");
}
public static void main(String[] args) {
DispatcherExctor dispatcherExctor = new DispatcherExctor(new ExectorA());
//委托执行
dispatcherExctor.doSomething();
}
}
/**
* 委托人
*
* @author xw
* @date 2019/9/24 17:00
*/
public class DispatcherExctor implements IExector {
//被委托人的引用
private IExector exector;
public DispatcherExctor(IExector exector) {
this.exector = exector;
}
@Override
public void doSomething() {
System.out.println("指定委托他人干活...");
exector.doSomething();
}
}
public static void main(String[] args) {
//受托人接任务
DispatcherExctor dispatcherExctor = new DispatcherExctor(new ExectorA());
//受托人委托执行人执行
dispatcherExctor.doSomething();
}
- 委派模式和工厂模式的区别?
- 工厂模式是生产固定的产品,针对具体的结果(产品);
委派模式针对的是具体的执行者,只需要满足执行标准(实现相同的接口) - 工厂模式返回的一个实例对象,关心的是Bean;
委派模式是具体执行方法,关心的是方法。 - 工厂模式可以看做固定的委派模式
- 与代理模式的区别?
策略模式
1、最终执行结果是固定的。
2、执行过程和执行逻辑不一样。
原型模式
1、首先有一个原型。
2、数据内容相同,但对象实例不同(完全两个不同的内存地址)。
模板模式
- 流程是固定的,不同实例有些不同
完成一件事情,有固定的数个步骤,但是每个步骤根据对象的不同,而实现细节不同;
就可以在父类中定义一个完成该事情的总方法,按照完成事件需要的步骤去调用其每个步骤的实现方法。每个步骤的具体实现,由子类完成。