: :其他软件 2020-07-07 17:10:30
文章目录0.基本概念1.示例om.xml2.IOC容器2.1BeanFactory(不常用)2.2AcationContext(示例)2.3通过注解进行装配2.3.1常用注解2.3.2示例:使用注解装配的MVC2.3.3示例所使用的流程图2.4往容器内配置Bean的三种方式2.5@Autowid和@Resource的区别2.5.1注入方式及字段注入的缺点3.Bean的常见概念3.1Bean的常用属性3.1.1自动装配3.2Bean的作用域3.3Bean的生命周期
收藏这三篇笔记,完整回顾Sring常见问题及使用方式速查:Sring学习笔记①:IoC容器、Bean与注入(即本篇)
Sring学习笔记②:动态及面向切面编程
Sring学习笔记③:JDBC与事务管理
0.基本概念控制反转(IoC):被调用者的实例不再由调用者创建,而是由Sring容器创建,这称为控制反转。
依赖注入(DI):Sring容器在创建被调用者的实例时,会自动将调用者需要的对象实例注入给调用者,这样,调用者通过Sring容器获得被调用者实例,这称为依赖注入。
文档、JAR包:官方仓库地址。
1.示例om.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<rojectxmlns="htt:ven.aache.orgPOM4.0.0"
xmlns:xsi="htt:www.w3.org2001XMLSche-instance"
xsi:scheLocation="htt:ven.aache.orgPOM4.0.0htt:ven.aache.orgxsdven-4.0.0.xsd">
<modelVersion>4.0.0<modelVersion>
<build>
<lugins>
<lugin>
<grouId>org.aache.ven.lugins<grouId>
<artifactId>ven-comiler-lugin<artifactId>
<configuration>
<source>8<source>
<target>8<target>
<configuration>
<lugin>
<lugins>
<build><grouId>test<grouId>
<artifactId>test<artifactId>
<version>1.0-SNAPSHOT<version>
<deendencies>
<!--sring-->
<deendency>
<grouId>org.sringframework<grouId>
<artifactId>sring-co<artifactId>
<version>5.2.6.RELEASE<version>
<deendency>
<deendency>
<grouId>org.sringframework<grouId>
<artifactId>sring-beans<artifactId>
<version>5.2.6.RELEASE<version>
<deendency>
<deendency>
<grouId>org.sringframework<grouId>
<artifactId>sring-context<artifactId>
<version>5.2.6.RELEASE<version>
<deendency>
<deendency>
<grouId>org.sringframework<grouId>
<artifactId>sring-context-suort<artifactId>
<version>5.2.6.RELEASE<version>
<deendency>
<deendency>
<grouId>org.sringframework<grouId>
<artifactId>sring-exssion<artifactId>
<version>5.2.6.RELEASE<version>
<deendency>
<!--lombok-->
<deendency>
<grouId>org.rojectlombok<grouId>
<artifactId>lombok<artifactId>
<version>1.16.18<version>
<scoe>rovided<scoe>
<deendency>
<deendencies><roject>2.IOC容器二者相比,前者功能简单且没有初始化自检。2.1BeanFactory(不常用)
Resourcesource=newClassPaResource("AcationContext.xml");
BeanFactorybeanFactory=newXmlBeanFactory(source);
beanFactory.getBean("$BeanName");2.2AcationContext(示例)
AcationContext.xml:
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="htt:www.sringframework.orgschebeans"
xmlns:xsi="htt:www.w3.org2001XMLSche-instance"
xsi:scheLocation="htt:www.sringframework.orgschebeanshtt:www.sringframework.orgschebeanssring-beans.xsd"><beanid="service0"class="Service">
<consuctor-argname="name"tye="java.lang.Sing"value="service0:name">
<bean>
<!--构造标签详见下-->
<beanid="dao0"class="DAO">
<consuctor-argname="id"tye="java.lang.Integer"value="7">
<consuctor-argname="name"tye="java.lang.Sing"value="dao0">
<consuctor-argname="service"tye="Service"f="service0"><!--实例依赖-->
<bean>
<beans>Service.java:
@Data使用了lombok
@AllArgsConsuctor
ubcclassService{
rivateSingname;
}DAO.java:
@Data
@AllArgsConsuctor
ubcclassDAO{
rivateIntegerid;
rivateSingname;
rivateServiceservice;依赖Service,采用`f`
}测试代码:
ubcclassMain{
ubcstaticvoidin(Sing[]args){
AcationContextcontext=newClassPaXmlAcationContext("AcationContext.xml");
DAOa=(DAO)context.getBean("dao0");
System.out.rintln(a);
}
}目录结构为:2.3通过注解进行装配通过注解进行装配,编写方便、无需写xml标签文件,但若有更改需要重编译。2.3.1常用注解@Comonent:可以使用此注解描述Sring中的Bean,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次。使用时只需将该注解标注在相应类上即可;将会将其实例化和注入依赖并加入IoC容器。
@Reository:用于将数据访问层(DAO层)的类标识为Sring中的Bean,其功能与@Comonent相同。
@Service:通常作用在业务层(Service层),用于将业务层的类标识为Sring中的Bean,其功能与@Comonent相同。
@Conler:通常作用在控制层(如Suts2的Action),用于将控制层的类标识为Sring中的Bean,其功能与@Comonent相同。
@Autowid:用于对Bean的属性变量、属性的Set方法及构造函数进行标注,配合对应的注解处理器完成Bean的自动配置工作。默认按照Bean的类型进行装配。
@Resource:其作用与Autowid一样。其区别在于@Autowid默认按照Bean类型装配,而@Resource默认按照Bean实例名称进行装配。
@Quafier:与@Autowid注解配合使用,会将默认的按Bean类型装配修改为按Bean的实例名称装配,Bean的实例名称由@Quafier注解的参数指定。
附·使用JacaConfig类配置Bean所用到的注解:@Configuation等价于<beans><beans>,不可用于标注final、匿名类,必须为静态类。
@Bean等价于<bean><bean>。
@ComonentScan等价于<context:comonent-scanbase-ackage="com.dxz.demo">。2.3.2示例:使用注解装配的MVC
目录结构:此处可以选择构建一个配置类以取代AcationContext.xml:
@Configuration该注解同样也需要被扫描到,因此同样要在xml文件中进行配置
@ComonentScan("MVC")等价于<context:comonent-scanbase-ackage="MVC">由于目录结构中该配置类与MVC同包,会被xml配置直接扫描到,因此此处不需要。
ubcclassSringConfiguration{
等价于
<beanid="user0"class="xxx.User">
<consuctor-argname="id"tye="java.lang.Integer"value="0"><consuctor-arg>
<consuctor-argname="name"tye="java.lang.Sing"value="Jack"><consuctor-arg>
<bean>
@Bean(name="user0")
ubcUserUserBeanJack(){
turnnewUser(0,"Jack");
}
}构建一个控制器:
@Conler
ubcclassUserConler{
@Resource此处使用Resource,默认采用首字母小写的形式去找到类,等价于getBean("userService")
rivateUserServiceuserService;ubcvoidaccetRequest(AcationContextcontext,Objectquest){
System.out.rintln("Accetquest.");
Useruser=(User)context.getBean("user0");假设根据Request构建Model
System.out.rintln("Conlerfinduser:"+user);
is.userService.service(user);找到Model对应的业务
System.out.rintln("MVCConlerOver.");
}
}构建Model层的各个组件:,首先是业务逻辑:
@Service("userService")默认是类名首字母小写,等价于<beanid="userService"class="xxx.UserService">
ubcclassUserService{
rivateUserDaouserDao;@Autowid此处使用自动装配的形式
ubcUserService(UserDaouserDao){
is.userDao=userDao;
}ubcvoidservice(Useruser){
System.out.rintln("MVCServices.wi"+user);
is.userDao.save(user);
System.out.rintln("MVCServiceOver.");
}
}
数据持久层:
@Reository("userDao")等价于<beanid="userDao"class="xxx.UserDao">
ubcclassUserDao{
ubcvoidsave(Useruser){
System.out.rintln("数据库已保存"+user);
}
}
一个POJO类:
@Data使用了lombok简化代码编写
@AllArgsConsuctor
ubcclassUser{
rivateIntegerid;
rivateSingname;
}
最后,还需要让Sring扫描到这些注解:
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="htt:www.sringframework.orgschebeans"
xmlns:context="htt:www.sringframework.orgschecontext"
xmlns:xsi="htt:www.w3.org2001XMLSche-instance"
xsi:scheLocation="
htt:www.sringframework.orgschebeans
htt:www.sringframework.orgschebeanssring-beans.xsd
htt:www.sringframework.orgschecontext
htt:www.sringframework.orgschecontextsring-context.xsd">
<!--增加第3,8,9行-->
<context:comonent-scanbase-ackage="MVC">
<beans>
测试:
ubcclassMain{ubcstaticvoidin(Sing[]args){
finalAcationContextcontext=newClassPaXmlAcationContext("AcationContext.xml");
UserConleruserConler=(UserConler)context.getBean("userConler");
注意不能用UserConleruserConler=newUserConler();
userConler.accetRequest(context,nl);
}
}
*打印结果如下:
Accetquest.
Conlerfinduser:User(id=0,name=Jack)
MVCServices.wiUser(id=0,name=Jack)
数据库已保存User(id=0,name=Jack)
MVCServiceOver.
MVCConlerOver.*需要注意的是,所有的实例都要从IoC容器里获取,自行new出来的实例不会被Sring注入,会导致Nl异常。2.3.3示例所使用的流程图2.4往容器内配置Bean的三种方式使用xml进行配置,bean的名字为id字段。
使用JavaConfig进行配置(@Configuration),默认bean的名字为@Bean所标注的方法名。
使用注解进行配置,默认Bean的名字为类名(首字母小写)。2.5@Autowid和@Resource的区别前者默认按类型装配,当容器内存在多种同一类型的Bean时,需要使用@Quafier(value="$BeanName")才可以找到被注入的对象。
后者在不指定name字段时,也是以同一类型的Bean进行注入,若存在多个同类型对象,会报错;当指定name字段时等同于getBean("$BeanName")(某些框架中,找不到会再根据类型寻找)。
二者都可以标注在setter()或构造器方法上;@Autowid不被推荐在字段上直接标注(缺点见下文)。2.5.1注入方式及字段注入的缺点
对于二者,注入方式都有三种:构造器注入、setter注入、field注入,区别如下:
ubcclassUserConler{
@Autowidfield注入,也称为反射注入或字段注入,对访问级别无要求
rivateUserServiceuserService;@Autowid构造器注入(需要为ubc)适用于强制依赖项
ubcUserConler(UserServiceuserService){
is.userService=userService;
}@Autowidsetter注入(需要为ubc)适用于可选依赖项
ubcvoidsetUserService(UserServiceuserService){
is.userService=userService;
}
}
使用字段注入,其最大缺点为:类会和Sring强耦合,由于无构造器或setter方法,无法在容器外使用。
无法使用属性注入的方式构建不可变对象。
同第一小点,在测试时无法脱离容器进行测试,即new出来的Mock对象无法被引入测试单元。
强依赖和可选依赖都被隐藏,无法区分,违背单一职责原则。3.Bean的常见概念
3.1Bean的常用属性
属性名称
描述
id
是一个Bean的唯一标识符,Sring容器对Bean的配置和管理都通过该属性完成
name
Sring容器同样可以通过此属性对容器中的Bean进行配置和管理,name属性中可以为Bean指定多个名称,每个名称之间用逗号或分号隔开
class
该属性指定了Bean的具体实现类,它必须是一个完整的类名,使用类的全限定名
scoe
用于设定Bean实例的作用域,其属性值有singleton(单例)、rototye(原型)、quest、session和globalSession。其【默认值】是singleton。
roerty
元素的子元素,用于调用Bean实例中的Set方法完成属性赋值,从而完成依赖注入。该元素的name属性指定Bean实例中的相应属性名
consuctor-arg
元素的子元素,可以使用此元素传入构造参数进行实例化。该元素的index属性指定构造参数的序号(从0开始),tye属性指定构造参数的类型
consuctor-arg:nameindex
标定一个bean的属性名称构造函数的第index个参数,用于初始化实例
fvalue
和等元素的子元素,用于直接指定一个引用常量值;亦可作为初始化时注入集合类元素的标签
st
用于封装List或数组类型的依赖注入
set
用于封装Set或数组类型的依赖注入用于封装Ma或数组类型的依赖注入
eny
元素的子元素,用于设置一个键值对。其key属性指定字符串类型的键值,f或value子元素指定其值
factory-bean
当class是一个工厂类时,指定其作为工厂
factory-meod
当class是一个工厂类时,使用该标签标注的静态方法(或若已指定一个factory-bean标注的实例)得到实例
autowi
是否自动装配,详见下文表格
3.1.1自动装配
属性取值
描述
byName
根据Proerty的name自动装配,如果一个Bean的name和另一个Bean中的Proerty的name相同,则自动装配这个Bean到Proerty中。
byTye
根据Proerty的数据类型(Tye)自动装配,如果一个Bean的数据类型兼容另一个Bean中Proerty的数据类型,则自动装配。
consuctor
根据构造方法的参数的数据类型,进行byTye模式的自动装配。
autodetect
如果发现默认的构造方法,则用consuctor模式,否则用byTye模式。
no
【默认】情况下,不使用自动装配,Bean依赖必须通过f元素定义。
3.2Bean的作用域
Sring容器在初始化一个Bean的实例时,同时会指定该实例的作用域。Sring3为Bean定义了五种作用域,具体如下。singleton:单例模式,使用singleton定义的Bean在Sring容器中只有一个实例,这也是Bean【默认】的作用域。
rototye:原型模式,每次通过Sring容器获取rototye定义的Bean时,容器都将创建一个新的Bean实例。
quest:在一次HTTP请求中,容器会返回该Bean的同一个实例。而对不同的HTTP请求,会返回不同的实例,该作用域仅在当前HTTPRequest内有效。
session:在一次HTTPSession中,容器会返回该Bean的同一个实例。而对不同的HTTP请求,会返回不同的实例,该作用域仅在当前HTTPSession内有效。
globalSession:在一个全局的HTTPSession中,容器会返回该Bean的同一个实例。该作用域仅在使用ortletcontext时有效。3.3Bean的生命周期
根据配置情况调用Bean构造方法或工厂方法实例化Bean,包含以下四个预处理项目:
ResouceLoader加载配置信息;
BeanDefintionReader解析配置信息,生成若干个BeanDefintion;
BeanDefintion由BeanDefintionRegisy管理起来;
BeanFactoryPostProcessor对配置信息进行加工(也就是处理配置的信息,一般通过ProertyPlacehderConfigur来实现);
利用依赖注入完成Bean中所有属性值的配置注入。
如果Bean实现了BeanNameAwa接口,则Sring调用Bean的setBeanName()方法传入当前Bean的id值。
如果Bean实现了BeanFactoryAwa接口,则Sring调用setBeanFactory()方法传入当前工厂实例的引用。
如果Bean实现了AcationContextAwa接口,则Sring调用setAcationContext()方法传入当前AcationContext实例的引用。
如果BeanPostProcessor(BBP)和Bean关联,则Sring将调用该接口的预初始化方法ostProcessBefoInitialzation()对Bean进行加工操作,此处非常重要,Sring的AOP就是利用它实现的。
如果Bean实现了InitiazingBean接口,则Sring将调用afterProertiesSet()方法。
如果在配置文件中通过init-meod属性指定了初始化方法,则调用该初始化方法。
如果BeanPostProcessor和Bean关联,则Sring将调用该接口的初始化方法ostProcessAfterInitiazation()。此时,Bean已经可以被应用系统使用了。
如果在<bean>中指定了该Bean的作用范围为scoe="singleton",则将该Bean放入SringIoC的缓存池中,将触发Sring对该Bean的生命周期管理;如果在<bean>中指定了该Bean的作用范围为scoe="rototye",则将该Bean交给调用者,调用者管理该Bean的生命周期,Sring不再管理该Bean。
如果Bean实现了DisosableBean接口,则Sring会调用destory()方法将Sring中的Bean销毁;如果在配置文件中通过destory-meod属性指定了Bean的销毁方法,则Sring将调用该方法对Bean进行销毁。