Spring使用工厂模式可以通过BeanFactory或ApplicationContext创建bean对象。
两者对比:
Spring中bean的默认作用域就是singleton。除了singleton作用域,Spring bean还有下面几种作用域:
Spring实现单例的方式:
xml格式:
注解:@Scope(value = "singleton")
核心提示点:Spring下默认的bean均为singleton,可以通过singleton=“true|false” 或者 scope=“?”来指定
Spring通过ConcurrentHashMap实现单例注册表的特殊方式实现单例模式。Spring实现单例的核心代码如下:
// 通过 ConcurrentHashMap(线程安全) 实现单例注册表
private final Map singletonObjects = new ConcurrentHashMap(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));
}
}
}
Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用JDK Proxy去进行代理了,这时候Spring AOP会使用Cglib,这时候Spring AOP会使用Cglib生成一个被代理对象的子类来作为代理。
1、JDK动态代理
利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,
在调用具体方法前调用InvokeHandler来处理。
2、CGLiB动态代理
利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
如下图所示:
Spring如何选择用JDK还是CGLiB?
当然你也可以使用AspectJ,Spring AOP已经继承了AspectJ,AspectJ应该算的上是java生态系统中最完整的AOP框架了。
Spring AOP和AspectJ AOP有什么区别?
Spring AOP属于运行时增强,而AspectJ是编译时增强。Spring AOP基于代理,而AspectJ基于字节码操作。
Spring AOP已经集成了AspectJ,AsectJ应该算的上是Java生态系统中最完整的AOP框架了。AspectJ相比于Spring AOP功能更加强大,但是Spring AOP相对来说更简单,如果我们的切面比较少,那么两者的性能差异不大。但是当切面太多的话,最好选择AspectJ,它比Spring AOP快很多。
模板方法模式是一种行为设计模式,它定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变一个算法的结构即可重定义该算法的默写特定步骤的实现方式。例如:
public abstract class Template {
//这是我们的模板方法
public final void TemplateMethod(){
PrimitiveOperation1();
PrimitiveOperation2();
PrimitiveOperation3();
}
protected void PrimitiveOperation1(){
//当前类实现
}
//被子类实现的方法
protected abstract void PrimitiveOperation2();
protected abstract void PrimitiveOperation3();
}
public class TemplateImpl extends Template {
@Override
public void PrimitiveOperation2() {
//当前类实现
}
@Override
public void PrimitiveOperation3() {
//当前类实现
}
}
Spring中jdbcTemplate、hibernateTemplate等以Template结尾的对数据库操作的类,它们就使用到模板模式。一般情况下,我们都是使用继承的方式来实现模板模式,但是Spring并没有使用这种方式,而是使用Callback模式与模板方法配合,既达到了代码复用的效果,同时增加了灵活性。
观察者设计模式是一种对象行为模式。它表示的是一种对象与对象之间具有依赖关系,当一个对象发生改变时,这个对象锁依赖的对象也会做出反应。Spring事件驱动模型就是观察者模式很经典的应用。
Spring事件流程总结:
例如:
// 定义一个事件,继承自ApplicationEvent并且写相应的构造函数
public class DemoEvent extends ApplicationEvent{
private static final long serialVersionUID = 1L;
private String message;
public DemoEvent(Object source,String message){
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
// 定义一个事件监听者,实现ApplicationListener接口,重写 onApplicationEvent() 方法;
@Component
public class DemoListener implements ApplicationListener{
//使用onApplicationEvent接收消息
@Override
public void onApplicationEvent(DemoEvent event) {
String msg = event.getMessage();
System.out.println("接收到的信息是:"+msg);
}
}
// 发布事件,可以通过ApplicationEventPublisher 的 publishEvent() 方法发布消息。
@Component
public class DemoPublisher {
@Autowired
ApplicationContext applicationContext;
public void publish(String message){
//发布事件
applicationContext.publishEvent(new DemoEvent(this, message));
}
}
适配器设计模式将一个接口转换成客户希望的另一个接口,适配器模式使得接口不兼容的那些类可以一起工作,其别名为包装器。在Spring MVC中,DispatcherServlet根据请求信息调用HandlerMapping,解析请求对应的Handler,解析到对应的Handler(也就是我们常说的Controller控制器)后,开始由HandlerAdapter适配器处理。
为什么要在Spring MVC中使用适配器模式?
Spring MVC中的Controller种类众多不同类型的Controller通过不同的方法来对请求进行处理,有利于代码的维护拓展。
装饰模式:动态的给一个对象添加一些额外的职责,就增加功能来说,装饰者到相比子类更加灵活。
Spring 的 ApplicationContext 中配置所有的 DataSource
。 这些 DataSource 可能是各种不同类型的, 比如不同的数据库: Oracle、 SQL Server、 MySQL 等, 也可能是不同的数据源: 比如Apache 提 供 的 org.apache.commons.dbcp.BasicDataSource 、 Spring 提 供 的org.springframework.jndi.JndiObjectFactoryBean 等。 然后 SessionFactory 根据客户的每次请求, 将 DataSource 属性设置成不同的数据源, 以到达切换数据源的目的。
在spring的命名体现:Spring 中用到的包装器模式在类名上有两种表现: 一种是类名中含有 Wrapper
, 另一种是类名中含有Decorator
。 基本上都是动态地给一个对象添加一些额外的职责。
Spring 框架的资源访问接口就是基于策略设计模式实现的。该接口提供了更强的资源访问能力,Spring框架本身大量使用了Resource接口来访问底层资源。Resource接口本身没有提供访问任何底层资源的实现逻辑,针对不同的额底层资源,Spring将会提供不同的Resource实现类,不同的实现类负责不同的资源访问类型。
Spring 为 Resource 接口提供了如下实现类:
UrlResource:访问网络资源的实现类。
ClassPathResource:访问类加载路径里资源的实现类。
FileSystemResource:访问文件系统里资源的实现类。
ServletContextResource:访问相对于 ServletContext 路径里的资源的实现类.
InputStreamResource:访问输入流资源的实现类。
ByteArrayResource:访问字节数组资源的实现类。
这些 Resource 实现类,针对不同的的底层资源,提供了相应的资源访问逻辑,并提供便捷的包装,以利于客户端程序的资源访问。