备注:applicationListener
 
Spring简介
Spring是一个开源Java开发框架,有很好的扩展性。
优点:
1.轻量级基础版本只有2MB
2.IOC松耦合,Spring 中的 org.springframework.beans 包和 org.springframework.context 包构成了Spring 框架 IOC 容器的基础。
控制反转 依赖注入(构造器/Setter/接口注入)
3.AOP
4.容器
5.MVC框架;
模块:core、bean、context、JDBC、ORM、JMS等,至今已集成了 20 多个模块。
核心容器:context(beanFactory)应用上下文,beanFactory使得Spring成为一个容器;
ApplicationContext 接口对 BeanFactory(是一个子接口)进行了扩展,beanFactory是在bean模块下面的,而ApplicationContext是在context模块下面
 
Spring有以下主要的命名空间:context、beans、jdbc、tx、aop、mvc和aso。
Spring作用域:single(默认单例的模式由 bean factory 自身来维护)、prototype、request、session、globalSession
 
 
加载bean流程
写在前面:Spring 创建对象分为三个过程:
1、创建对象实例 Object obj = new Object() 或者 Object obj = new Object(xxx);
AbstractAutowireCapableBeanFactory#createBeanInstance
2、依赖注入: obj.setXxx(xxx) {多个属性就是 foreach}
AbstractAutowireCapableBeanFactory#populateBean
3、Spring bean 扩展方法:init-method,BeanPostProcess,XXXAware 扩展 (可见Bean的生命周期)
AbstractAutowireCapableBeanFactory#initializeBean
 
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml"); ac.getBean(XXX.class);
以下是三种较常见的 ApplicationContext 实现方式:
1.ClassPathXmlApplicationContext:从 classpath 的 XML 配置文件中读取上下文,并生成
2.FileSystemXmlApplicationContext :由文件系统中的 XML 配置文件读取上下文
3.XmlWebApplicationContext:由 Web 应用的 XML 文件读取上下文
 
ClassPathXmlApplicationContext存储内容
对象名
类型
作用
归属类
configResources
Resource[]
配置文件资源对象数组
ClassPathXmlApplicationContext
configLocations
String[]
配置文件字符串数组,存储配置文件路径
AbstractRefreshableConfigApplicationContext
beanFactory
DefaultListableBeanFactory
上下文使用的Bean工厂
AbstractRefreshableApplicationContext
beanFactoryMonitor
Object
Bean工厂使用的同步监视器
AbstractRefreshableApplicationContext
applicationListeners
Set<ApplicationListener>
Spring提供的事件管理机制中的应用监听器
AbstractApplicationContext
startupShutdownMonitor
Object
refresh方法和destory方法公用的一个监视器,避免两个方法同时执行
AbstractApplicationContext
 
public ClassPathXmlApplicationContext(String configLocation) throws BeansException { this(new String[] {configLocation}, true, null); }
 
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { // 没什么太大的作用,设置一下父级ApplicationContext,这里是null super(parent); // 1.将指定的Spring配置文件的路径存储到本地 2.解析Spring配置文件路径中设置为自己需要的系统变量 setConfigLocations(configLocations); // refresh()方法是整个Spring Bean加载的核心,方法是加锁的,这么做的原因是避免多线程同时刷新Spring上下文; if (refresh) { refresh(); } }
 
public void refresh() throws BeansException, IllegalStateException { // 保证了在调用refresh()方法的时候无法调用close()方法 synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // 这步比较关键,这步完成后,配置文件就会解析成一个个 Bean 定义,注册到 BeanFactory 中, // 当然,这里说的 Bean 还没有初始化,只是配置信息都提取出来了, // 注册也只是将这些信息都保存到了注册中心(说到底核心是一个 beanName-> beanDefinition 的 map) ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean prepareBeanFactory(beanFactory); try { // 这里是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化 // 具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类或做点什么事 postProcessBeanFactory(beanFactory); // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法 invokeBeanFactoryPostProcessors(beanFactory); // 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别 // 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization // 两个方法分别在 Bean 初始化之前和初始化之后得到执行。注意,到这里 Bean 还没初始化 registerBeanPostProcessors(beanFactory); // 初始化当前 ApplicationContext 的 MessageSource initMessageSource(); // 初始化当前 ApplicationContext 的事件广播器 initApplicationEventMulticaster(); // 从方法名就可以知道,典型的模板方法(钩子方法), // 具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前) onRefresh(); // 注册事件监听器,监听器需要实现 ApplicationListener 接口 registerListeners(); // 重点,重点,重点 // 初始化所有的 singleton beans //(lazy-init 的除外) finishBeanFactoryInitialization(beanFactory); // 最后,广播事件,ApplicationContext 初始化完成 finishRefresh(); } catch (BeansException ex) { // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } } }
 
prepareRefresh方法
protected void prepareRefresh() { this.startupDate = System.currentTimeMillis(); synchronized (this.activeMonitor) { this.active = true; } if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } }
这个方法功能比较简单,顾名思义,准备刷新Spring上下文,其功能注释上写了:
1、设置一下刷新Spring上下文的开始时间
2、将active标识位设置为true
 
obtainFreshBeanFactory方法
obtainFreshBeanFactory方法的作用是获取刷新Spring上下文的Bean工厂,其代码实现为:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
其核心是第二行的refreshBeanFactory方法,这是一个抽象方法,有AbstractRefreshableApplicationContext和GenericApplicationContext这两个子类实现了这个方法,看一下上面ClassPathXmlApplicationContext的继承关系图即知,调用的应当是AbstractRefreshableApplicationContext中实现的refreshBeanFactory,其源码为:
protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
这段代码的核心是第7行,这行点出了DefaultListableBeanFactory这个类,这个类是构造Bean的核心类,这个类的功能会在下一篇文章中详细解读,首先给出DefaultListableBeanFactory的继承关系图:
对象名
类型
作用
归属类
aliasMap
Map<String, String>
存储Bean名称->Bean别名映射关系
SimpleAliasRegistry
singletonObjects
Map<String, Object>
存储单例Bean名称->单例Bean实现映射关系
DefaultSingletonBeanRegistry
singletonFactories
 Map<String, ObjectFactory>
存储Bean名称->ObjectFactory实现映射关系
DefaultSingletonBeanRegistry
earlySingletonObjects
Map<String, Object>
存储Bean名称->预加载Bean实现映射关系
DefaultSingletonBeanRegistry
registeredSingletons
Set<String> 
存储注册过的Bean名
DefaultSingletonBeanRegistry
singletonsCurrentlyInCreation 
Set<String>
存储当前正在创建的Bean名 
DefaultSingletonBeanRegistry
beanDefinitionMap
Map<String, BeanDefinition> 
存储Bean名称-->Bean定义映射关系 
DefaultListableBeanFactory
beanDefinitionNames
List<String>
存储Bean定义名称列表 
DefaultListableBeanFactory
factoryBeanObjectCache
Map<String, Object>
存储Bean名称->FactoryBean接口Bean实现映射关系
FactoryBeanRegistrySupport
beanPostProcessors
List<BeanPostProcessor>
存储 BeanPostProcessor接口实现列表
AbstractBeanFactory
ObjectFactory: 一个工厂,它可以在调用时返回一个对象实例(可能是共享的或独立的)
 
finishBeanFactoryInitialization方法
中调用了DefaultListableBeanFactory的preInstantiateSingletons方法,本文针对preInstantiateSingletons进行分析,解读一下Spring是如何初始化Bean实例对象出来的。
DefaultListBeanFactory.getBean(beanName)
 
doGetBean方法构造Bean流程
上面把getBean之外的代码都分析了一下,看代码就可以知道,获取Bean对象实例,都是通过getBean方法,getBean方法最终调用的是DefaultListableBeanFactory的父类AbstractBeanFactory类的doGetBean方法,因此这部分重点分析一下doGetBean方法是如何构造出一个单例的Bean的。重点就是调用了ObjectFactory的getObject()方法来获取到单例Bean对象,方法的实现是调用了createBean方法,createBean方法是AbstractBeanFactory的子类AbstractAutowireCapableBeanFactory的一个方法,看一下它的方法实现:
createBean(beanName, mbd, args);
doCreateBean(beanName, mbd, args);
最后通过反射的方式实例化一个对象
 
 
初始化Bean流程图
 
 
初始化总结:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("");
1⃣️ResourceLoader加载XML配置信息后,由BeanDefinitionReader读取配置信息文件,把每个<bean>解析成BeanDefinition对象保存在注册表中( 然后放到Factory的map中(这一步就是所谓的注册),这样以后程序就可以直接从Factory中拿Bean信息了)。
2⃣️容器首先扫描注册表取出工厂后处理器,对注册表中的BeanDefinition进行加工处理。
3⃣️Spring容器接着从注册表中取出加工过的BeanDefinition开始着手bean实例化的事情。
4⃣️实例化时,首先由BeanWapper对bean进行封装,配置属性。最后利用注册表中的Bean后处理器装饰打扮,装配出一个准备就绪的Bean来。(注册表就类似于一个Map<K,V>,把所有的bean,不管是业务bean,还是spring自己的bean,都放到注册表里,用的时候取出来)。
 
参考链接:
 
 
 
Java类的加载与初始化
加载(双亲委派)->验证->准备->解析(set)->初始化(创建类的实例)->使用->卸载
解析也有可能是发生在初始化在后,为了支持Java语言的运行时绑定(也称为动态绑定)
 
加载:
1、获取.class文件的二进制流
2、将类信息、静态变量、字节码、常量这些.class文件中的内容放入方法区中
3、在内存中生成一个代表这个.class文件的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。一般这个Class是在堆里的,不过HotSpot虚拟机比较特殊,这个Class对象是放在方法区中的
 
验证:确保.class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全
1、文件格式验证
2、元数据验证
3、字节码验证
4、符号引用验证
 
 
准备:准备阶段是正式为类变量分配内存并设置其初始值的阶段,这些变量所使用的内存都将在方法区中分配
不被final修饰的static变量,在准备阶段被赋值为0,直到初始化才会被具体赋值;若被final修饰,会在准备阶段就被赋值;
 
解析:解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。
 
初始化:
虚拟机会保证类的初始化在多线程环境中被正确地加锁、同步,即如果多个线程同时去初始化一个类,那么只会有一个类去执行这个类的<clinit>()方法,其他线程都要阻塞等待,直至活动线程执行<clinit>()方法完毕
 
 
循环依赖
三级缓存
protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return (singletonObject != NULL_OBJECT ? singletonObject : null); }
第一级缓存singletonObjects里面放置的是实例化好的单例对象。第二级earlySingletonObjects里面存放的是提前曝光的单例对象(没有完全装配好)。第三级singletonFactories里面存放的是要被实例化的对象的对象工厂。
一级缓存记录已完成;二级缓存记录正在装配中的;三级缓存记录即将装配的
 
spring处理对象相互依赖注入的问题(allowCircularReferences)
描述:循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方
Spring容器循环依赖包括构造器循环依赖和setter循环依赖
1、构造器循环依赖
构造器循环依赖:表示通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出BeanCurrentlyInCreationException异常表示循环依赖。
Spring容器将每一个正在创建的Bean 标识符放在一个“当前创建Bean池”中,Bean标识符在创建过程中将一直保持在这个池中,因此如果在创建Bean过程中发现自己已经在“当前创建Bean池”里时将抛出BeanCurrentlyInCreationException异常表示循环依赖;而对于创建完毕的Bean将从“当前创建Bean池”中清除掉。
 
2、setter循环依赖
1⃣️singleton: setter循环依赖:表示通过setter注入方式构成的循环依赖。
对于setter注入造成的依赖是通过Spring容器提前暴露刚完成构造器注入但未完成其他步骤(如setter注入)的Bean来完成的,而且只能解决单例作用域的Bean循环依赖。
如下代码所示,通过提前暴露一个单例工厂方法,从而使其他Bean能引用到该Bean。
addSingletonFactory(beanName, new ObjectFactory() { public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); } });
2⃣️非singleton: 对于prototype作用域Bean,Spring容器无法完成依赖注入,因为prototype作用域的Bean,Spring容器不进行缓存,因此无法提前暴露一个创建中的Bean。
3⃣️在Spring IOC中对于singleton作用域Bean,可以通过setAllowCircularReferences(false);来禁用循环引用:
(ps:我理解的就是有一个缓冲区ObjectFactory,如果可以在里面找到就直接返回,是否允许Bean 覆盖参数allowBeanDefinitionOverriding)
 
总结:
循环依赖是可以解决的,但是循环调用是无法解决的,除非有终结条件,否则就是死循环,最终导致内存溢出错误。
Spring 循环依赖需要满足三个条件:
1、setter 注入(构造器注入不能循环依赖)
2、singleton bean(非单例 bean 不支持)
3、AbstractAutowireCapableBeanFactory#allowCircularReferences 这个 boolean 属性控制是否可以循环,默认为 true。
 
当 A 创建的时候,会把 A 对应的 ObjectFactory 放在缓存中,当依赖注入的时候发现了 B 对象,调用 getBean() 方法获取 B 对象, 然后创建 B 对象,会把 B 对应的 ObjectFactory 放在缓存中。
此时 B 依赖 A ,然后再调用 getBean 获取 A 对象, 此时调用 AbstractBeanFactory#doGetBean 从缓存中获取到 A 对应的 ObjectFactory。
这样就避免了死循环,然后再创建成功之后删除 ObjectFactory 完成依赖注入。
思路:中间对象去解决循环依赖。
 
 
 
 
Bean的生命周期
Spring容器读取XML文件中bean的定义并实例化bean,在一个 bean 实例被初始化时,需要执行一系列的初始化操作以达到可用的状态。
Spring根据bean的定义设置属性值。
如果任何bean BeanPostProcessors 和该bean相关,Spring调用postProcessBeforeInitialization()方法。
如果该Bean实现了InitializingBean接口,调用Bean中的afterPropertiesSet方法。
如果bean有初始化函数声明,调用相应的初始化方法。
如果该Bean实现了BeanNameAware接口,Spring将bean的id传递给setBeanName()方法。
如果该Bean实现了BeanFactoryAware接口,Spring将beanfactory传递给setBeanFactory()方法。
如果任何bean BeanPostProcessors 和该bean相关,调用postProcessAfterInitialization()方法。
如果该bean实现了DisposableBean,调用destroy()方法。
 
Bean自身的方法 这个包括了Bean本身调用的方法和通过配置文件中<bean>的init-method和destroy-method指定的方法
Bean级生命周期接口方法 BeanNameAware、BeanFactoryAware、InitializingBean、DiposableBean等接口中的方法
容器级生命周期接口方法 这个包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。
 
 
 
 
>>> 自定义注解
@Documented : JavaDoc文档
@Target:标志此注解可以修饰在哪些地方,类,成员变量,方法...
@Retention:Annotation的生命周期,一般情况下,我们自定义注解的话,显然需要在运行期获取注解的一些信息。
 
 
双亲委派
(1)当前类加载器从自己已经加载的类中查询是否此类已经加载,如果已经加载则直接返回原来已经加载的类。
(2)如果没有找到,就去委托父类加载器去加载(如代码c = parent.loadClass(name, false)所示)。父类加载器也会采用同样的策略,查看自己已经加载过的类中是否包含这个类,有就返回,没有就委托父类的父类去加载,一直到启动类加载器。因为如果父加载器为空了,就代表使用启动类加载器作为父加载器去加载。
(3)如果启动类加载器加载失败(例如在$JAVA_HOME/jre/lib里未查找到该class),会使用拓展类加载器来尝试加载,继续失败则会使用AppClassLoader来加载,继续失败则会抛出一个异常ClassNotFoundException,然后再调用当前加载器的findClass()方法进行加载。
 
 好处:
(1)主要是为了安全性,避免用户自己编写的类动态替换 Java的一些核心类,比如 String。
(2)同时也避免了类的重复加载,因为 JVM中区分不同类,不仅仅是根据类名,相同的 class文件被不同的 ClassLoader加载就是不同的两个类。
 
自定义类加载器
继承ClassLoader,并覆盖findClass方法
 
 
Spring事务
 
事务传播属性propagation behavior
PROPAGATION_REQUIRED:表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务
PROPAGATION_REQUIRED_NEW:表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager
PROPAGATION_SUPPORTS:表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行
PROPAGATION_NOT_SUPPORTED:表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager
PROPAGATION_NEVER:表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常
PROPAGATION_MANDATORY:表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常
 
事务嵌套
现象:
在一个service方法中调用了另一个service方法,其中调用的第二个方法发生异常,标记为rollbackOnly,就算在第一个service中catch后还是会报异常。
获取连接 Connection con = DriverManager.getConnection()
开启事务con.setAutoCommit(true/false);
执行CRUD
提交事务/回滚事务 con.commit() / con.rollback();
关闭连接 conn.close();
使用Spring的事务管理功能后,我们可以不再写步骤 2 和 4 的代码,而是由Spirng 自动完成。 那么Spring是如何在我们书写的 CRUD 之前和之后开启事务和关闭事务的呢?解决这个问题,也就可以从整体上理解Spring的事务管理实现原理了。下面简单地介绍下,注解方式为例子
配置文件开启注解驱动,在相关的类和方法上通过注解@Transactional标识。
spring 在启动的时候会去解析生成相关的bean,这时候会查看拥有相关注解的类和方法,并且为这些类和方法生成代理,并根据@Transaction的相关参数进行相关配置注入,这样就在代理中为我们把相关的事务处理掉了(开启正常提交事务,异常回滚事务)。
真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。
 
 
事务管理器
Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。 
Spring事务管理器的接口是org.springframework.transaction.PlatformTransactionManager,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。此接口的内容如下:
public interface PlatformTransactionManager { //PlatformTransactionManager通过getTransaction(TransactionDefinition definition)方法来得到事务 TransactionStatus getTransaction(TransactionDefinition var1) throws TransactionException; void commit(TransactionStatus var1) throws TransactionException; void rollback(TransactionStatus var1) throws TransactionException; }
 
public interface TransactionDefinition { int getPropagationBehavior(); // 返回事务的传播行为 int getIsolationLevel(); // 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据 int getTimeout(); // 返回事务必须在多少秒内完成 boolean isReadOnly(); // 事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的 }
JDBC事务 org.springframework.jdbc.datasource.DataSourceTransactionManager
Hibernate事务 org.springframework.orm.hibernate3.HibernateTransactionManager
Java持久化API事务(JPA) org.springframework.orm.jpa.JpaTransactionManager
 
 
Spring AOP
AOP实现框架有Spring AOP、AspectJ(实现方式还是Spring AOP)......
 
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 
动态代理:在程序运行时,运用反射机制动态创建而成。
动态代理 与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成
 
概念:面向切面编程,通过动态代理给方法做增强处理。
在运行期间生成代理(静态代理),在运行期字节码加载前修改字节码(jdk/cglib),在运行期字节码加载后动态创建代理类的字节码(自定义加载器)
 
Spring会为每一个Bean创建一个对应的ProxyFactoryBean的FactoryBean来创建某个对象的代理对象。
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而cglib(Code Generation Library)动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
字节码的动态生成,会继承目标对象,所以不能用final修饰
 
AOP术语:连接点Joinpoint,切入点Pointcut,通知Advice(前中后),切面Aspect
 
1.JDK代理
class Proxy implements Invocation{ private Object object; invoke(Object proxy, Method method, Object[] args){ return method.invoke(object,args); } } new newProxyInstance(classLoader.getClass().getClassLoader(),interfaces.getClass().getInterfaces(),Proxy);
 
2.CGLIB代理
class Proxy implements methodInterceptor{ private Object object; public Object createProxyObject(Object targetObject) { this.targetObject = targetObject; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.targetObject.getClass()); enhancer.setCallback(this); return enhancer.create(); } intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy){ return method.invoke(object,args); } } new Proxy().createProxyObject(new A());
 
 
代理模式并没有做到切面与业务代码的解耦。虽然将切面的逻辑独立进了代理类,但是决定是否使用切面的权利仍然在业务代码中。这才导致了上面这种麻烦。
 
异步Async
spring异步线程池的接口类,其实质是Java.util.concurrent.Executor
 
 
Spring设计模式
1.单例模式,默认实例都是单例模式;
2.代理模式,在AOP和remoting中用的较多;
3.模板模式:数据库connection,以及在各种BeanFactory以及ApplicationContext实现中也都用到了,还有RestTemplate, JmsTemplate, JpaTemplate,TransactionTemplate;
4.策略模式:Jdk代理还是Cglib代理;
5.适配器模式:Stream;
6.工厂:在各种BeanFactory以及ApplicationContext创建;
7.观察者:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新
spring中Observer模式常用的地方是listener的实现。如ApplicationListener;
8.迭代器:collection实现了Iterable,所以都可以用迭代器;
9.门面:其核心为外部与一个子系统的通信必须通过一个统一的外观对象进行,使得子系统更易于使用。如slf4j;
10.委派模式:Spring 提供了 DispatcherServlet 来对请求进行分发
 
模版模式和策略模式的区别:
 
 
Spring单例
// 饿汉 private static Single single = new Single(); // 懒汉 private static Single single; // 会有并发问题 public static Single getInstance(){ if(single == null){ single = new Single(); } return single; } single volatile 防止重排序带来的问题 public Single getSingle(){ if(single == null){ synchronized (Single.class){ if(single == null){ single = new Single(); } } } return single; }
 
SpringMVC流程
SpringMVC是一种基于Spring实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,使用了MVC架构模式的思想,将web层进行职责解耦,并管理应用所需对象的生命周期,为简化日常开发,提供了很大便利。
DispatchSerlet -> HandleMapping -> HandleApater -> controller -> ModelView
 
优质参考链接:
 

最新文章

  1. 【转】Oracle执行计划解释
  2. bootstrap的下拉框在firefox界面不友好的处理
  3. jquery 按钮效果 正常、移上、按下
  4. centos 6.4下的postgresql 9.2使用
  5. 如何使用 Microsoft Azure Media Services 现场直播,(Live Streaming) 直播流媒体系统
  6. delete删除多表
  7. string内存管理
  8. Lucene.net 从创建索引到搜索的代码范例
  9. 如何使用Prism框架的EventAggregator在模块间进行通信
  10. log4net使用简介
  11. 帝国cms栏目死变量
  12. WebPack实例与前端性能优化
  13. 使用Gradle创建java web项目
  14. UIAlertController高级之嵌入其他控件
  15. Viso设置背景
  16. mysql 时间戳格式化函数FROM_UNIXTIME和UNIX_TIMESTAMP函数的使用说明
  17. js时间戳与时间日期间相互转换
  18. MongDB增删改查
  19. react 之 reflux 填坑
  20. Storm原理

热门文章

  1. C语言是什么
  2. 关于C语言指针的讨论
  3. docker搭建etcd集群环境
  4. JS异步操作概述(转)
  5. 可落地的DDD(3)-如何利用DDD进行微服务的划分
  6. Go的基础类型
  7. Trie树的java实现
  8. Java实现简易聊天室
  9. C#8.0——异步流(AsyncStream)
  10. Mysql 单表查询-排序-分页-group by初识