JavaEE学习笔记3
对应代码
地址
Note for JavaEE-Day3
关于Spring
Spring是针对复杂的EJB最早于2002提出的JavaEE设计开发工具。其基本结构可以表示为下图:

Figure 1
Spring优势
- Spring在企业级开发中占有率很高,大于90%
- Spring可以简化企业级应用开发
- Spring可以有效整合其他技术来促进开发
Spring生态
- SpringFramework: 框架核心,其他技术的基础
- SpringBoot: 超热门的简化spring开发工具
- SpringCloud: 为分布式应用所提出的微服务框架
- …
Spring控制反转
松/紧耦合编程
这里的耦合即程序中连个模块的相互关联程度。紧耦合编程模块之间的相关度高,维护成本大;松耦合编程模块之间的关联少,而通过接口联系,即在欲关联的模块外部设置依赖关系。
一个松耦合的例子是一个类中某属性为另一个类,不在这个类的业务层new另一个类,而是通过在外部新生成这两个类的对象,再通过set方法设置属性。
Spring控制反转容器
在实例的创建和初始化中,IOC容器中的实例被称为beans,依赖注入会在bean之间进行。
创建Spring工程
这里介绍使用maven创建spring工程,分为如下步骤:
-
创建maven工程,并向
pom.xml
中添加SpringFramework依赖,添加后更新maven插件。
例如:
<dependencies>
<!-- 添加SpringFramework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<!-- 添加junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
-
在资源文件夹中添加spring配置文件
applicationContext.xml
。 - 创建java类,并在spring配置文件中声明bean,参考代码如下:
<!--2.配置bean-->
<!--bean标签标示配置bean
id属性标示给bean起名字
class属性表示给bean定义类型-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<!--7.配置server与dao的关系-->
<!--property标签表示配置当前bean的属性
name属性表示配置哪一个具体的属性
ref属性表示参照哪一个bean-->
<property name="bookDao" ref="bookDao"/>
</bean>
- 启动IOC容器,使用bean启动方法,参考代码如下:
public static void main(String[] args) {
// 3.获取IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 4.获取bean(根据bean配置id获取)
// BookDao bookDao = (BookDao) ctx.getBean("bookDao");
// bookDao.save();
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
}
bean的生命周期
Scope of beans
scope是声明bean时的一个可选参数,取值为
singleton
或
prototype
,默认为前者。前者标注的bean在控制反转生成实例时,多次调用返回的是同一实例,即引用地址相同。而后者标注的bean会生成多个不同的实例,即引用地址不同。
特别指出,我在这里翻看了spring源码,其中有
beanFactory.preInstantiateSingletons();
这样一个方法,spring会逐个bean检查,对于
singleton
对应的bean,它会预先实例化。所以这就有了后面使用bean实例化bookDao也调用bookService的初始化方法。
使用Factory实例化
使用bean实例化有以下四种方法:
<!--方式一:构造方法实例化bean-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<!--方式二:使用静态工厂实例化bean-->
<bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>
<!--方式三:使用实例工厂实例化bean-->
<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
<!--方式四:使用FactoryBean实例化bean-->
<bean id="userDao2" class="com.itheima.factory.UserDaoFactoryBean"/>
关于这四种方法的解释如下:
- 方法一: 朴素方法,与前面创建spring工程中的启动IOC容器一致。
-
方法二: 本质上就是在
OrderDaoFactory
类中有一个静态的
getOrderDao
方法,在这个方法中返回新实例化的
boookDao
-
方法三: 与方法二相比
getUserDao
不是静态方法,但仍返回新实例化的
boookDao
。第一句bean的声明为声明factory,第二句为声明factory的方法。 -
方法四: 类
UserDaoFactoryBean
使用接口
FactoryBean
,类内部有新实例化
boookDao
的方法。
初始化方法与销毁方法
可以在声明bean时加入
init-method
和
destroy-method
参数,其指向类的对应方法将分别在bean实例化对象的初始化阶段和销毁阶段调用,后者只适用于单例(
singleton
)对象。实例代码为:
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
InitializingBean与DisposableBean接口
bean提供有InitializingBean与DisposableBean接口可覆写其中方法,其调用与
init-method/destroy-method
相似。示例如下:
@Override
public void destroy() throws Exception {
System.out.println("service destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
依赖注入
我所理解的依赖注入就是设置bean对应类中的属性(基本类型或引用类型),其有如下几种方法。
通过setter注入
所谓setter就是对应类中一个设置类中属性的方法,而通过其注入只需要在对应bean中进行property配置即可。
<!--注入简单类型-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<!--property标签:设置注入属性-->
<!--name属性:设置注入的属性名,实际是set方法对应的名称-->
<!--value属性:设置注入简单类型数据值-->
<property name="connectionNum" value="100"/>
<property name="databaseName" value="mysql"/>
</bean>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<!--注入引用类型-->
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<!--property标签:设置注入属性-->
<!--name属性:设置注入的属性名,实际是set方法对应的名称-->
<!--ref属性:设置注入引用类型bean的id或name-->
<property name="bookDao" ref="bookDao"/>
<property name="userDao" ref="userDao"/>
</bean>
通过构造方法注入
不同于调用setter方法,还可以通过构造方法设置属性。具体方法是使用
constructor-arg
标签替代
property
标签,
name
参数指示形参名称,从而根据参数名称注入依赖。形式如下:
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<!--根据构造方法参数名称注入-->
<constructor-arg name="connectionNum" value="10"/>
<constructor-arg name="databaseName" value="mysql"/>
</bean>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="userDao" ref="userDao"/>
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
这里的
name
参数可以替换为
type
或
index
,前者指示根据参数类型注入,后者指示根据参数位置(索引)注入。
为集合属性添加依赖
针对典型的集合属性如数组、list、set、map、properties,其添加依赖形式与传统形式相似,使用对应标签指示集合内容即可,形如:
<!--数组注入,int类型-->
<property name="array">
<array>
<value>100</value>
<value>200</value>
</array>
</property>
<!--list集合注入,string类型-->
<property name="list">
<list>
<value>itcast</value>
<value>boxuegu</value>
</list>
</property>
自动注入依赖
自动注入依赖不需要手动注入属性,在对应bean中加入
autowire
参数即可,形式如下:
<!--autowire属性:开启自动装配,通常使用按类型装配-->
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byName"/>
autowire
参数值可选
byType
或
byName
,前者将会寻找与被注入bean的setter中参数类型相同的bean进行注入(多个相同会抛出
NoUniqueBeanDefinitionException
异常),后者将会寻找与被注入bean的setter方法名所对应的bean进行注入(如果没找到就不注入)。
IOC容器
IOC容器类

Figure 2
IOC容器中类的接口与继承关系如Figure 2所示,由其可见我们常用的
ApplicationContext
类继承自
BeanFacory
类,而其他常用的类如
ClassPathXmlApplicationContext
和
FileSystemXmlApplicationContext
都是调用了
ApplicationContext
接口,其使用方法如下:
//1.加载类路径下的配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.从文件系统下加载配置文件
ApplicationContext ctx = new FileSystemXmlApplicationContext(
"D:\\workspace\\spring_10_container\\src\\main\\resources\\applicationContext.xml");
获取Bean
获取bean有三种方法,分别是通过bean的名字、生成方法以及类型,其代码如下:
//1. getBean by Name
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
//2. getBean by Name(Generic method)
BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
//3. getBean by Type
BookDao bookDao = ctx.getBean(BookDao.class);
Spring注解
这里主要介绍ppt中对应的注解:
-
@Configuration
。声明当前类为spring配置类,而后可以用IOC容器类
AnnotationConfigurationContext((配置类名).class)
加载该配置类以初始化spring容器。 -
@ComponetScan({})
。注解于spring配置类前,用以设置bean扫描路径,多个路径写为字符串数组格式。 -
@Component
。用以实现bean的注入,即声明bean,从而使其可以被spring扫描或实例化。 -
@Scope("")
。设置bean的声明周期,
singleton
或
prototype
。 -
@PostConstruct
。设置bean的初始化方法。 -
@PreDestroy
。设置bean的销毁方法。 -
@Bean("")
。注解bean中方法,相当于实例化工厂实例化bean。 -
@Autowired
。可注解于字段、初始化方法以及set方法,以自动注入依赖。 -
@Qualifier("")
。注解于
@Autowired
后字段或方法前,用于按名字注入。 -
@PropertySource({""})
。设置资源文件扫描路径。 -
@Value("${资源文件中的变量名}")
。设置属性注入。 -
@Controller
。指示bean是springMVC中的一个controller。 -
@Service
。指示bean是一个service。 -
@Repository
。指示bean是在SpringData中的一个库。