IOC

IoC 全称为 Inversion of Control,翻译为 “控制反转”,这是一种思想,控制权转交给他人。

所谓Spring IoC ,就是由 Spring IOC 容器来负责对象的生命周期和对象之间的关系
在没有spring的时候,需要某个对象,一般都是已new的方式去创建,这个过程复杂而又繁琐,每个环节都要自己去把控,自己管理整个对象的生命周期,而且对象与对象之间都是耦合在一起的。

Bean

Spring IoC容器管理一个或多个bean。这些bean是使用您提供给容器的配置元数据创建的(例如,以XML定义的形式 )。

别名

1
<alias name="fromName" alias="toName"/>

实例化

Bean创建对象。

构造函数实例化

1
<bean id="userDao" class="com.ds.dao.UserDaoImpl"/>

静态工厂方法实例化

1
2
3
<bean id="userDao"
class="com.ds.dao.UserDaoFactory"
factory-method="createInstance"/>

实例工厂方法实例化

1
2
3
4
<bean id="userDaoFactory" class="com.ds.dao.UserDaoFactory" />
<bean id="userDao"
factory-bean="userDaoFactory"
factory-method="createDaoInstance"/>

懒加载

懒加载,顾名思义,只有用的时候才会加载。
在spring中,配置懒加载优先级:

1
2
3
4
5
6
7
8
9
<beans>                           <bean />                   </beans>  immediately
<beans> <bean lazy-init="true" /> </beans> lazy
<beans> <bean lazy-init="false"/> </beans> immediately
<beans default-lazy-init="true"> <bean/> </beans> lazy
<beans default-lazy-init="true"> <bean lazy-init="true" /> </beans> lazy
<beans default-lazy-init="true"> <bean lazy-init="false" /> </beans> immediately
<beans default-lazy-init="false"> <bean /> </beans> immediately
<beans default-lazy-init="false"> <bean lazy-init="true" /> </beans> lazy
<beans default-lazy-init="false"> <bean lazy-init="false" /> </beans> immediately

注入

spring就是把对象与对象的耦合变为,对象与spring的耦合,把对象与对象之间进行解耦。

原三层架构实例如下:
dao数据访问层:

1
2
3
public interface UserDao {
void getUser();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class UserDaoImpl implements UserDao{
private String name;

public UserDaoImpl(){
this.name = "";
}

public UserDaoImpl(String name){
this.name = name;
}

@Override
public void getUser() {
System.out.println("name:"+name);
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

service逻辑处理层:

1
2
3
public interface UserService {
void getUser();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class UserServiceImpl implements UserService{

//private UserDao dao = new UserDao();
private UserDao dao;

@Override
public void getUser() {
dao.getUser();
}

public UserService setUser(UserDao dao){
this.dao = dao;
return this;
}
}

ui表示层或调用层:

1
2
3
4
5
public class MyTest {
public static void main(String[] args) {
new UserServiceImpl().setUser(new UserDaoImpl()).getUser();
}
}

对外开放dao的创建,不在service中new,暴露给调用者。这就很符合ioc的思想。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式,在spring中实现控制反转的是ioc容器,其实现方法是依赖注入(Dependency Injection)
spring已经提供了几种对象依赖的方式:构造方法注入、stter方法注入、接口注入。

通过xml配置

构造器注入

构造器注入,顾名思义就是被注入的对象通过在其构造方法中声明依赖对象的参数列表,让外部知道它需要哪些依赖对象。

1
2
3
<bean id="userDao" class="com.ds.dao.UserDaoImpl">
<constructor-arg name="name" value="2222"/>
</bean>
1
2
3
4
5
6
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");//默认根目录resources
new UserServiceImpl().setUser((UserDao) context.getBean("userDao")).getUser();;
}
}

构造器注入方式比较直观,对象构造完毕后就可以直接使用。

循环依赖,如果只是用构造器注入,可能会创建无法解决的循环注入。
例如:A类通过构造函数注入需要B类的实例,而B类通过构造函数注入需要A类的实例。如果您将A类和B类的bean配置为相互注入,则Spring IoC容器会在运行时检测到此循环引用,并抛出 BeanCurrentlyInCreationException。

  • 解决方式
    • 通过修改源码,解决逻辑上的问题。
    • 该用get,set注入。

setter 方法注入

对于 JavaBean 对象而言,我们一般都是通过 getter 和 setter 方法来访问和设置对象的属性。所以,当前对象只需要为其所依赖的对象提供相对应的 setter 方法,就可以通过该方法将相应的依赖对象设置到被注入对象中。如下:

1
2
3
<bean id="userDao" class="com.ds.dao.UserDaoImpl">
<property name="name" value="1111"></property>
</bean>

相比于构造器注入,setter 方式注入会显得比较宽松灵活些,它可以在任何时候进行注入(当然是在使用依赖对象之前)。
property优先级比constructor-arg要低,会覆盖constructor-arg的赋值。

接口方式注入

接口方式注入需要被依赖的对象实现接口,并重写某些方法来实现功能。

1
2
3
4
5
6
public class MyTest extends HttpServlet{
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}

注入了HttpServletRequest和HttpServletResponse。

自动注入

项目过大的话,配置property是一件非常繁琐的事,所以就有自动注入的配置了。

要确保唯一bean命名。
否则转为明确的注入

1
2
<beans default-autowire="byName">
</bean>

排除自动注入

1
2
<beans default-autowire-candidates="true"/> 集合排除自动注入
<bean autowire-candidate="true" /> 单独排除自动注入 内层覆盖外层配置

p名称空间

简化XML Schema文档定义中的property配置方式

1
2
3
4
5
6
<bean id="userDao" class="com.ds.dao.UserDaoImpl">
<property name="name" value="1111"></property>
</bean>
<!-- p名称空间替换property -->
<bean id="userDao1" class="com.ds.dao.UserDaoImpl"
p:name="2222"/>

c名称空间

简化XML Schema文档定义中的constructor-arg配置方式

1
2
3
4
5
6
7
8
9
10
<bean id="userDao1" class="com.ds.dao.UserDaoImpl"/>
<bean id="userDao2" class="com.ds.dao.UserDaoImpl"/>
<bean id="userDao3" class="com.ds.dao.UserDaoImpl">
<constructor-arg name="userDao1" ref="userDao1"/>
<constructor-arg name="userDao2" ref="userDao2"/>
</bean>
<!-- c名称空间替换constructor-arg -->
<bean id="userDao4" class="com.ds.dao.UserDaoImpl"
c:userDao1-ref="userDao1"
c:userDao2-ref="userDao2"/>

声明周期

初始化
  • 用注释的方法 @PostConstruct,作用于方法,不能有参数。
  • 实现InitializingBean接口,重写afterPropertiesSet()方法,官方不推荐,耦合了spring
  • xml配置bean时,选用init-method属性,自定义初始化方法,不能有参数。
    • 可以在beans配置default-init-method=”init”,内部bean类直接实现init方法,就可以定制初始化,不需要每个bean单独配置。
销毁
  • 用注释的方法 @PreDestroy,作用于方法,不能有参数。
  • 实现DisposableBean接口,重写destroy()方法。
  • xml配置bean时,选用destroy-method属性,自定义初始化方法,不能有参数。
    • 可以在beans配置default-destroy-method=”destroy”,内部bean类直接实现destroy方法,就可以定制初始化,不需要每个bean单独配置。
抽象接口

Lifecycle是spring提供的抽象声明周期接口,当ApplicationContext启动和停止时,会自动调用Lifecycle实现的对应方法。

1
2
3
4
5
public interface Lifecycle {
void start();
void stop();
boolean isRunning();
}

LifecycleProcessor继承了Lifecycle,多了两个方法。用于处理容器的refreshed和closed事件。

1
2
3
4
public interface LifecycleProcessor extends Lifecycle {
void onRefresh();
void onClose();
}

SmartLifecycle实现Lifecycle和Phased,用于处理对象的依赖关系,哪些bean需先初始化,哪些需要在哪些bean完成某些动作后再进行初始化和销毁,getPhase表示为执行顺序,返回int。
启动时,最小的phase最先启动,停止时相反。因此,若对象实现了SmartLifecycle接口,它的getPhase()方法返回Integer.MIN_VALUE,那么该对象最先启动,最后停止。若是getPhase()方法返回Integer.MAX_VALUE,那么该方法最后启动最先停止。关于phase的值,常规的并未实现SmartLifecycle接口的Lifecycle对象,其值默认为0。因此,负phase值表示要在常规Lifecycle对象之前启动(在常规Lifecycyle对象之后停止),使用正值则恰恰相反。

1
2
3
4
5
6
7
public interface Phased {
int getPhase();
}
public interface SmartLifecycle extends Lifecycle, Phased {
boolean isAutoStartup();
void stop(Runnable callback);
}

SmartLifecycle中stop()方法有一个回调参数。所有的实现在关闭处理完成后会调用回调的run()方法,相当于开启异步关闭功能。
LifecycleProcessor接口在Spring中的默认实现是DefaultLifecycleProcessor类,该类会为每个回调等待超时,默认超时是30秒。
可以重写该类默认的参数,该类在容器内默认bean名称是lifecycleProcessor。比如修改超时时间:

1
2
3
4
<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
<!-- timeout value in milliseconds -->
<property name="timeoutPerShutdownPhase" value="10000"/>
</bean>

通过注解

  • 扫描
    • @ComponentScan 自动扫描,一般配置在启动类上
  • 配置
    • @Configuration 配置类
  • 注册到容器
    • @Bean 注册bean,可以作用于方法,对方法返回的对象注册到容器中
    • @Component 注册bean,只能作用于类
      • @Controller 控制器,注入服务,封装了@Component,单纯用于分层
      • @Service 服务,注入dao,封装了@Component,单纯用于分层
      • @Repository dao,实现访问数据,封装了@Component,单纯用于分层
  • 注入
    • @Autowired 按byType自动注入,不用实现get,set方法
      • 允许null值 required=false
      • 按名称匹配,需与@Qualifier(“名称”)连用
    • JSR-250规范定义
      • @Resource
        • 默认按byName自动注入
        • 设置name 按byName自动注入
        • 设置type 按byType自动注入
        • 同时设置name,type,同时起作用,name+type唯一匹配
      • @PostConstruct 自定义初始化
      • @PreDestroy 自定义销毁
    • JSR-330规范定义
      • @Inject 比@Autowired功能少,没有使用的必要
  • 作用域
    • @Scope
      • singleton 单例
      • prototype 多例
      • session 会话
      • request 请求
      • application 应用
      • websocket
      • globalSession portlet Session声明周期
  • 事务
    • @Transactional

拓展接口

  • InitializingBean
    • void afterPropertiesSet()
      • bean初始化之后执行,可修改属性,自定义初始化
  • DisposableBean
    • void destroy()
      • bean销毁时执行
  • BeanNameAware
    • void setBeanName(String var1)
      • 获取bean的id,当前类
  • ApplicationContextAware
    • void setApplicationContext(ApplicationContext applicationContext)
      • 获取ApplicationContext实例
  • BeanFactoryAware
    • void setBeanFactory(BeanFactory beanFactory)
      • 获取BeanFactory实例
  • FactoryBean
    • 自定义生成bean,不通过容器产生,由getObjeact返回
    • Object getObject()
      • 返回生成的bean对象
    • Class<?> getObjectType
      • 返回bean的类型
    • boolean isSingleton
      • 返回是否为单例
  • BeanPostProcessor
    • 后置处理器,可以获取beanName(非id),每个bean的产生都会执行
    • Object postProcessBeforeInitialization(Object bean, String beanName)
      • 对象实例化之后执行
      • 对象初始化之前执行
    • Object postProcessAfterInitialization(Object bean, String beanName)
      • 对象实例化之后执行
      • 对象初始化之后执行
    • 在beafore和after之间会检查是否有实现InitializingBean的afterPropertiesSet方法以及是否xml中有配置init-method并执行初始化方法。init-method会覆盖afterPropertiesSet。
  • BeanFactoryPostProcessor
    • beanFactory后置处理器,只在factory生成时执行一次。
    • void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory)
      • 可以修改context中的beanFactory,这时候beanFactory已经standard initialization了
      • 方法执行时机,所有的bean definitions已经加载,但没有bean实例化
      • 可通过修改bean definitions来修改bean
  • InstantiationAwareBeanPostProcessor
    • Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
      • 对象实例化之前,如果返回非null,代表对象覆盖要生成对象,则下只执行postProcessAfterInitialization
    • boolean postProcessAfterInstantiation(Object bean, String beanName)
      • 对象实例化之后属性复制前执行,如果返回false则下面的属性填充不执行,反之执行
    • PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
    • PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
      • 属性注入到目标对象之前执行,通过此方法修改对象属性,方法执行的前提是postProcessAfterInstantiation返回true
  • PropertyPlaceholderConfigurer
    • 将properties文件中的配置加载,并可替换xml中的$特殊字符
  • PropertyOverrideConfigurer
    • 将properties文件中的配置加载,可替换bean属性的值
  • ThreadFactory
    • spring版本的线程工厂
  • AbstractRoutingDataSource
    • 动态数据源

拓展接口调用时机

  • BeanFactory创建
  • BeanFactory创建之后,Bean实例化之前
    • BeanFactoryPostProcessor.postProcessBeanFactory
    • InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
  • Bean实例化
  • Bean实例化之后
    • InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
  • Bean属性赋值前
    • InstantiationAwareBeanPostProcessor.postProcessProperties
    • InstantiationAwareBeanPostProcessor.postProcessPropertyValues
  • Bean属性赋值
  • Bean属性赋值之后
    • BeanNameAware.setBeanName
    • BeanFactoryAware.setBeanFactory
    • ApplicationContextAware.setApplicationContext
  • Bean初始化之前
    • BeanPostProcessor.postProcessBeforeInitialization
  • Bean初始化
    • 注解PostConstruct
    • InitializingBean.afterPropertiesSet
    • xml中配置的init-method
  • Bean初始化之后
    • BeanPostProcessor.postProcessAfterInitialization
  • 容器初始化完成和使用
  • Bean销毁
    • DisposableBean.setBeanName
    • xml中配置的destroy-method方法

ClassPathXmlApplicationContext


该图为ClassPathXmlApplicationContext 的继承架构图,可以看到最上层的BeanFactory,创建bean的核心。ResourceLoader,资源加载器。ApplicationContext贯穿了整个spring框架。

Resource体系

Resource,对资源的抽象,它的每一个实现类都代表了一种资源的访问策略,如ClasspathResource 、 URLResource ,FileSystemResource 等。有了资源,就应该有资源加载,Spring 利用 ResourceLoader 来进行统一资源加载。

BeanFactory 体系

BeanFactory 是一个非常纯粹的 bean 容器,它是 IOC 必备的数据结构,其中 BeanDefinition 是她的基本结构,它内部维护着一个 BeanDefinition map ,并可根据 BeanDefinition 的描述进行 bean 的创建和管理。
BeanFacoty 有三个直接子类 ListableBeanFactory、HierarchicalBeanFactory 和 AutowireCapableBeanFactory,DefaultListableBeanFactory 为最终默认实现,它实现了所有接口。

Beandefinition 体系

BeanDefinition 用来描述 Spring 中的 Bean 对象。

BeandefinitionReader体系

BeanDefinitionReader 的作用是读取 Spring 的配置文件的内容,并将其转换成 Ioc 容器内部的数据结构:BeanDefinition。

ApplicationContext体系

这个就是大名鼎鼎的 Spring 容器,它叫做应用上下文,与我们应用息息相关,它继承 BeanFactory,所以它是 BeanFactory 的扩展升级版,如果BeanFactory 是屌丝的话,那么 ApplicationContext 则是名副其实的高富帅。由于 ApplicationContext 的结构就决定了它与 BeanFactory 的不同,其主要区别有:

  • 继承 MessageSource,提供国际化的标准访问策略。
  • 继承 ApplicationEventPublisher ,提供强大的事件机制。
  • 扩展 ResourceLoader,可以用来加载多个 Resource,可以灵活访问不同的资源。
  • 对 Web 应用的支持。

IoC初始化

Ioc的初始化,就要了解spring的启动顺序。Post not found: java/spring/20200710