- [ ] 控制反转(Ioc)和依赖注入(DI)
IOC是一个原则,而不是一个模式,以下模式等实现了Ioc原则
Spring IOC容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件、注解即可,完全不用考虑对象是如何被创建出来的。
DI(依赖注入)是实现控制反转的一种设计模式,依赖注入就是将实例变量传入到一个对象中去。
- [ ] 工厂设计模式
Spring使用工厂模式可以通过BeanFactory 或 ApplicationContext 创建bean对象
- BeanFactory: 延迟注入(使用到某个bean的时候才会注入),相比于ApplicationContext来说会占用更少的内存,程序启动速度更快。
- ApplicationContext::容器启动的时候,不管你用没用到,一次性创建所有bean,BeanFactory仅提供最基本的依赖注入支持, ApplicationContext扩展了BeanFactory,除了有BeanFactory的功能还有额外更多功能,所以一般开发者使用ApplicationContext更多
ApplicationContext的三个实现类:
- ClassPathContext: 把上下文文件当成类路径资源
- FileSystemXmlApplication:从文件系统中的xml文件载入上下文定义信息
- XmlWebApplicationContext:从Web系统中的xml文件载入上下文定义信息
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext context = new FileSystemXmlApplicationContext(
"C:/work/IOC Containers/springframework.applicationcontext/src/main/resources/bean-factory-config.xml");
HelloApplicationContext obj = (HelloApplicationContext) context.getBean("helloApplicationContext");
obj.getMsg();
}
}
- [ ] 单例设计模式
在我们的系统中,有一些对象其实我们只需要一个,比如:线程池、缓存、对话框、注册表、日志对象、充当打印机、显卡等设备驱动程序的对象。事实上,这一类对象只能有一个实例,如果制造出多个实例就可能导致一些问题的出现,比如:程序的行为异常、资源使用过量、或者不一致的结果
使用单例模式的好处:
- 对于频发使用的对象,可以省略创建对象所花费的时间,这对那些重量级对象而言,是非常可观的一笔开销;
- 由于new操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻GC压力,缩短GC停顿时间。
Spring中bean的默认作用域是singleton(单例)的。Spring实现单例的方法:
<bean id="userService" class="top.snailclimb.UserService" scope="singleton" />
注解:@Scope(value = "singleton")
Spring通过ConcurrentHashMap实现单例注册表的特殊方式实现单例模式。Spring实现单例的核心代码:
// 通过 ConcurrentHashMap(线程安全) 实现单例注册表
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "'beanName' must not be null");
synchronized (this.singletonObjects) {
// 检查缓存中是否存在实例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//...省略了很多代码
try {
singletonObject = singletonFactory.getObject();
}
//...省略了很多代码
// 如果实例对象在不存在,我们注册到单例注册表中。
addSingleton(beanName, singletonObject);
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
//将对象添加到单例注册表
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
}
}
}
- [ ] 代理设计模式
代理模式在AOP的应用
AOP(面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或者责任(例如事务管理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用JDK Prixy去进行代理了,这个时候Spring AOP会使用Cglib生成一个被代理对象的子类来作为代理
- [ ] 观察者模式
观察者模式是一种对象行为型模式。它表示的是一种对象与对象之间具有依赖关系,当一个对象发生改变的时候,这个对象所依赖的对象也会做出反应。Spring事件驱动模式就是观察者模式。
Spring事件驱动模型非常有用,在很多场景都可以解耦我们的代码。比如我们每次添加商品的时候都需要重新更新商品索引,这个时候就可以利用观察者模式来解决这个问题了。
Spring事件驱动模型中的三种角色
事件角色
ApplicationEvent (org.springframework.context包下)充当事件的角色,这是一个抽象类,它继承了java.util.EventObject并实现了java.io.Serializable接口。
Spring中默认存在以下事件,他们都是对ApplicationContextEvent的实现(继承自ApplicationContextEvent):
- ContextStartedEvent:ApplicationContext启动后触发的事件
- ContextStoppedEvent:ApplicationContext停止后触发的事件
- ContextRefreshedEvent: ApplicationContext 初始化或刷新完成后触发的事件
- ContextClosedEvent: ApplicationContex:关闭后触发的事件。
ApplicationListener
充当了事件监听者角色,它是一个接口,里面只定义了一个 onApplicationEvent()
方法来处理ApplicationEvent
。ApplicationListener
接口类源码如下,可以看出接口定义看出接口中的事件只要实现了 ApplicationEvent
就可以了。所以,在 Spring中我们只要实现 ApplicationListener
接口的 onApplicationEvent()
方法即可完成监听事件
package org.springframework.context;
import java.util.EventListener;
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E var1);
}
事件发布者
ApplicationEventPublisher充当了事件的发布者,它也是一个接口。
@FunctionalInterface
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
this.publishEvent((Object)event);
}
void publishEvent(Object var1);
}
Spring的事件流程总结:
- 定义一个事件:实现一个继承自 ApplicationEvent,并且写相应的构造函数
- 定义一个事件监听者:实现ApplicationListener接口,重写onApplicationEvent方法
- 使用事件发布者发布消息:可以通过ApplicationEventPublisher 的publishEvent()方法发布消息。
//定义一个事件,继承自ApplicationEvent并且写相应的构造函数
public class demo extends ApplicationEvent {
private static final long serialVersionUID = 1L;
private String message;
public demo(Object source,String message){
super(source);
this.message=message;
}
public String getMessage(){
return message;
}
//定义一个事件监听者,实现ApplicationListener接口,重写onApplicationEvent()方法
@Component
public class DemoListener implements ApplicationListener<demo>{
//使用onApplicationEvent接收消息
@Override
public void onApplicationEvent(demo demo){
String msg = demo.getMessage();
System.out.println("接收到的消息是:"+msg);
}
}
//发布事件,可以通过ApplicationEventPublisher 的publishEvent()方法发布消息
@Component
public class DemoPublisher {
@Autowired
ApplicationContext applicationContext;
public void publish(String message){
//发布事件
applicationContext.publishEvent(new demo(this,message));
}
}
}
总结:
Spring框架中用到了哪些设计模式?
- 工厂模式:Spring使用工厂模式通过BeanFactory、ApplicationContext创建bean对象
- 单例模式:Spring 中的Bean默认都是单例的
- 模板模式:Spring中jdbcTemplate、hibernateTemplate等Template结尾的对数据库操作的类,它们就使用了模板模式
- 代理模式:Spring AOP功能的实现