官网:
https://spring.io
优秀的java开源框架。
作用:项目管理。 管理组件(对象 DAO,Service,Controller)。
设计思路:践行工厂模式,打造一个工厂,通过工厂完成对项目的管理。
学习思路:分析项目中的问题,引入spring解决方案,打造更好的项目形态。
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-context-supportartifactId>
<version>4.3.6.RELEASEversion>
dependency>
spring 核心jar,其中核心容器 jar:beans、context、context-support、core、expression |
---|
配置文件作用:描述哪些组件需要spring生产,管理
文件位置:
resources目录
文件名称:随意. 常用名 :
applicationContext.xml
beans.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDAO" class="com.zhj.dao.UserDAOImpl">bean>
<bean id="userService" class="com.zhj.service.UserServiceImpl">bean>
....
beans>
工厂接口:
ApplicationContext
实现类:
ClassPathXmlApplicationContext
// 启动工厂,注意:需要指定配置文件位置
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
// 从工厂中获取 标识为"userDAO"的组件
UserDAO userDAO = (UserDAO)context.getBean("userDAO")
Schema:配置文件的schema(规范)。
作用:统一配置方式,开发者和框架采用同一套配置语法。向框架传达开发意图。
格式:xsd文件 (spring-beans-4.1.xsd,spring-context-4.1.xsd,…)
导入方式:spring的每种schema都有namespace作为标识;
:在配置文件中追加namespace,以及和namespace配套的location即可。如下
<beans xmlns="http://www.springframework.org/schema/beans"
http://www.springframework.org/schema/beans/spring-beans.xsd">
...
beans>
每种schema中,都在定义:允许出现哪些标签,标签的层级,标签的先后顺序,标签的属性。
每一种配置意图,都由规范中的 标签、属性来描述。
项目由一个个的组件组成,而组件之间都不是孤立的。会彼此依赖。
类之间的关系紧密程度,即耦合度。关系松散即弱耦合,关系密切即强耦合。
class A{
public void eat(){...}
}
class B{
public void fn2(Dog a){a.eat();...}
}
//如上B类中 直接关联了A类,则B类智能和A类协作,不能和其他类协作 ==> 强耦合
interface Animal{ public void eat();}
class Dog implements Animal{
public void fn1(){...}
}
class Test{
public void fn2(IA a){a.fn1();...}
}
//如上B类中只是和IA接口关联,则此时B类可以使用A类,也可以在完全不需要改动的情况下兼容所有IA的其他实现类。
//则B类 和 A类 的关系是松散的 ==> 弱耦合
关系处理不当时,可能会导致组件之间强耦合。
一旦强耦合:组件即陷入
不稳健
的状态,不稳健
的组件 将导致整个项目的形态极差。项目中的具体体现:Controller 依赖 Service 、Service 依赖 DAO 、…
spring介入后,可以以全新的方式处理依赖关系,
既保证依赖健全,又没有强耦合。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDAO" class="com.zhj.dao.UserDAOImpl">bean>
<bean id="userService" class="com.zhj.service.UserServiceImpl">
<property name="userDAO" ref="userDAO">property>
bean>
beans>
public class UserServiceImpl implements UserService{
//private UserDAO userDAO = new UserDAOImpl(); 不再强耦合UserDAOImpl
private UserDAO userDAO; //替换为接口
// set/get
public UserDAO getUserDAO() {
return userDAO;
}
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
思考:此时UserServiceImpl 和 UserDAOImpl的关系是否为弱耦合?
Inverse Of Controll
:控制反转反转了依赖关系的满足方式,由之前的自己创建依赖对象,变为由工厂推送。(变主动为被动,即反转)
解决了具有依赖关系的组件之间的强耦合,使得项目形态更加稳健
Dependency Injection
:依赖注入全新的依赖满足方式,体现在编码中就是全新的赋值方式 ==>
在工厂中为属性推送值
如:
在spring中关于IOC和DI的描述是这样的:
IOC(DI)
,即,是一码事
IOC 是思想
:指导我们在满足依赖时,应该有反转的设计。
DI 是手段
:实际操作时,就是在一次次的 注入
spring官方文档中,关于DI的解释:
This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies on its own by using direct construction of classes or the Service Locator pattern
- set注入:
- 借助set方法完成注入
- 构造注入 (了解)
- 借助构造方法完成注入
- 自动注入
- spring自动识别属性,并注入
<bean id="setDI" class="x.xx.XXX">
<property name="age" value="18">property>
<property name="name" value="zhj">property>
<property name="gender" value="true">property>
<property name="userDAO" ref="ud">property>
<property name="list">
<list>
<value>18value>
<ref bean="ud"/>
list>
property>
<property name="xxx">
<set>
<value>xxvalue>
set>
property>
<property name="map">
<map>
<entry key="name" value="zhj">entry>
<entry key="userDAO" value-ref="ud">entry>
map>
property>
<property name="prop">
<props>
<prop key="url">jdbc:oracle:xxxxprop>
props>
property>
bean>
<bean id="consDI" class="com.test.TestConstrutorDIComponent">
<constructor-arg index="0" type="java.lang.Integer" value="18">constructor-arg>
<constructor-arg index="1" type="java.lang.String" value="zhj">constructor-arg>
<constructor-arg index="2" type="java.lang.Boolean" value="true">constructor-arg>
bean>
<bean id="consDI04" class="com.qianfeng.di.ConsComponent">
<constructor-arg index="0" type="java.lang.Integer" value="4">constructor-arg>
<property name="name" value="yueqi"/>
<property name="gender" value="false"/>
bean>
不用在配置中 指定为哪个属性赋值,及赋什么值.
由spring自动根据某个 “原则” ,在工厂中查找一个bean,为属性注入属性值
<bean id="xx" class="xxx" autowire="byName">bean>
<bean id="xx" class="xxx" autowire="bytype">bean>
此处,掌握
byName
和byType
的概念即可。基于类型 自动注入时,如果存在多个此类型的bean,会报错。
通过调用无参构造,创建对象
<bean class="xx.xx.xxx.XXX" id="xxx">
// 反射
String classpath="com.zhj.domain.User";
Class user = Class.forName(classpath);
Constructor constructor = user.getConstructor();
User o = (User)constructor.newInstance();
- singleton:单例 ==> 默认
- 在同一个spring工厂中,一个bean只会创建一次对象。
- 多次getBean(),或多次注入使用的是同一个对象
- 随工厂创建 而创建,随工厂关闭而销毁
- prototype:多例 (原型)
- 每次getBean(),或注入都会重新创建对象
- 不随工厂创建 而创建,不随工厂关闭而销毁
- 被用到时才会创建对象
对象的状态:对象的成员变量值 即 对象的状态
无状态:不同的用户,不同的请求,对象的属性值不会发生改变
有状态:不同的用户,不同的请求,对象的属性值会发生改变有状态对象:多例模式
无状态对象:单例模式(一般都是单例的)
单例bean:构造(工厂启动)–>set(注入)–>init–>User–>destroy(工厂关闭)
多例bean:获取时才创建–>set–>init–>User–>不会随工厂关闭而销毁
针对的是复杂对象,无法直接生产
FactoryBean
:生产某一类对象
在工厂中有些bean,无法直接通过 简单的
生产。
比如:
Connection,SqlSessionFactory
FactoryBean:spring工厂中一种特殊的bean,可以生产对象。Spring工厂中的小作坊。
Spring支持如下方式:
// 1.实现FactoryBean
public class MySqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>{
public SqlSessionFactory getObject(){
//完成SqlSessionFactory的生产,并返回生产的对象
}
...
}
<bean id="sqlSessionFactory" class="com.zhj.factory.MySqlSessionFactoroyBean">bean>
// 2.静态工厂方法
public class MyFactoryBean {
public static User createUser(){
return new User();
}
}
<bean id="user" factory-method="createUser" class="com.zhj.factory.MyFactoryBean" scope="xx">bean>
// 3.工厂方法
public class MyFactoryBean {
public User createUser(){
return new User();
}
}
<bean id="userFactory" class="com.zhj.factory.bean.MyFactoryBean">bean>
<bean id="user" factory-bean="userFactory" factory-method="createUser" scope="xx">bean>
定义了如上任何一种后,测试:
//获取bean,此时获取的并不是FactoryBean,而是其生产的对象。
SqlSessionFactory sqlSessionFactory = (sqlSessionFactory)context.getBean("sqlSessionFactory");
//获取bean,此时获取的并不是FactoryBean,而是其生产的对象。
User user = (User)context.getBean("user");
工厂模式是编程中经常用到的一种模式。
它的主要优点有:
1> 可以使代码结构清晰,有效地封装变化。在编程中,产品类的实例化有时候是比较复杂和多变的,通过工厂模式,将产品的实例化封装起来,使得调用者根本无需关心产品的实例化过程,只需依赖工厂即可得到自己想要的产品。对调用者屏蔽具体的产品类。如果使用工厂模式,调用者只关心产品的接口就可以了,至于具体的实现,调用者根本无需关心。即使变更了具体的实现,对调用者来说没有任何影响。
2> 降低耦合度。产品类的实例化通常来说是很复杂的,它需要依赖很多的类,而这些类对于调用者来说根本无需知道,如果使用了工厂方法,我们需要做的仅仅是实例化好产品类,然后交给调用者使用。对调用者来说,产品所依赖的类都是透明的。
//简单工厂模式:
class SimpleFactory{
public Computer createOperate(string sig){
Computer com = null;
switch (sig){
case "1":
{
com = new Lenovo();
break;
}
case "2":
{
com = new Asus();
break;
}
}
return com;
}
}
// 如上方法如果是静态的,则为静态工厂模式
//上述简单工厂,存在问题,即如果有新的生产需要时,需要改动工厂类,则不符合设计模式中的开闭原则。改进如下:
//工厂方法模式:
// 1.定义接口
interface Computer{}
class ASUS implements Computer{}
class Lenovo implements Computer{}
// 2.定义工厂接口
interface ComputerFactory{Computer createComputer();}
// 3.如此在有新的生产需要时,每个工厂类依然稳定,只要添加新的工厂类即可
LenovoFactory implements ComputerFactory{
public Computer createComputer(){
return new Lenovo();
}
}
AsusFactory implements ComputerFactory{
public Computer createComputer(){
return new Asus();
}
}
//抽象工厂模式:
interface 水果{}
interface 蔬菜{}
class 本地水果 implements 水果{}
class 外地水果 implements 水果{}
class 本地蔬菜 implements 蔬菜{}
class 外地蔬菜 implements 蔬菜{}
interface factory{
//相对于工厂方法模式,抽象工厂模式有多个抽象产品,也就有多个抽象生产方法
//抽象工厂更像是工厂,而抽象方法更像是一个生产线
水果 createFruit();
蔬菜 createVeg();
}
//如下一样,当有新的蔬菜和水果需要生产时,现有的类不用改动,新加工厂类即可
class 本地Factory implements Factory{
public 水果 createFruit(String name){
new 本地水果(name);
}
public 蔬菜 createFruit(String name){
new 本地蔬菜(name);
}
}
class 外地Factory implements Factory{
public 水果 createFruit(String name){
new 外地水果(name);
}
public 蔬菜 createFruit(String name){
new 外地蔬菜(name);
}
}
Bean创建过程:运行过程,对应核心API,直到反射层面
new ClassPathXmlApplicationContext(String[] configLocations,boolean refresh,ApplicationContext parent){
//...;
refresh();//创建主流程
//...;
}
AbstractApplicationContext#refresh(){
//...;
// 创建BeanFactory,(DefaultListableBeanFactory)
// 并解析spring配置文件,进而加载BeanDefinitions
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//...;
finishBeanFactoryInitialization(beanFactory);//创建所有单例的bean
//...;
}
AbstractApplicationContext#finishBeanFactoryInitialization(){
//...;
beanFactory.preInstantiateSingletons();//创建所有单例的bean
//...;
}
DefaultListableBeanFactory#preInstantiateSingletons(){
for (String beanName : beanNames) {//遍历所有的beanName,挨个创建对象
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {//非抽象+单例+非延迟,则创建
if (isFactoryBean(beanName)) {
FactoryBean fb = getBean("&"+beanName);//获得工厂Bean对象本身
//....
getBean(beanName);//创建实际对象,此中会通过工厂Bean获得
}else{
getBean(beanName);//普通bean,直接创建对象
}
}
}
}
AbstractBeanFactory#getBean(){
return doGetBean(...);
}
AbstractBeanFactory#doGetBean(){
//....
if (mbd.isSingleton()) {
//注意:此处有回调 ObjectFactory#getObject()
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {//获得或创建单例的bean
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);//回调方法,创建bean
}
//...
}
}
}
DefaultSingletonBeanRegistry#getSingleton(beanName,singletonFactory){
synchronized (this.singletonObjects) {//枷锁,防止重复创建
Object singletonObject = this.singletonObjects.get(beanName);//尝试获取,如果有则不再创建
//....
singletonObject = singletonFactory.getObject();//回调doGetBean中内部类的方法,创建单例bean
//....
addSingleton(beanName, singletonObject);//记录已创建的单例bean,下次不再创建
}
}
//接:回调doGetBean中内部类“ObjectFactory”的getObject方法,创建单例bean
AbstractAutowireCapableBeanFactory#createBean(){
//.....
doCreateBean(beanName, mbdToUse, args);//创建单例bean
}
AbstractAutowireCapableBeanFactory#doCreateBean(){
//.....
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
}
AbstractAutowireCapableBeanFactory#createBeanInstance(){
//.....
return instantiateBean(beanName, mbd);//使用无参构造创建bean
}
AbstractAutowireCapableBeanFactory#instantiateBean(){
//.....
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
SimpleInstantiationStrategy#instantiate(){
//....
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);//获得构造方法对象
//....
return BeanUtils.instantiateClass(constructorToUse);//反射构建bean
}
) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
}
AbstractAutowireCapableBeanFactory#createBeanInstance(){
//.....
return instantiateBean(beanName, mbd);//使用无参构造创建bean
}
AbstractAutowireCapableBeanFactory#instantiateBean(){
//.....
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
SimpleInstantiationStrategy#instantiate(){
//....
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);//获得构造方法对象
//....
return BeanUtils.instantiateClass(constructorToUse);//反射构建bean
}