1.Spring
(1)Spring是什么?
是一个轻量级的、用来简化企业级应用开发的开发框架。
注:
a.简化开发:
Spring对常用的api做了简化,比如,使用Spring
jdbc来访问数据库,就不用再考虑如何获取连接、关闭连接、处理异常等等。
b.解耦:
Spring容器(Spring框架的一个模块)帮我们管理
对象(包括对象的创建及对象之间的依赖关系),
这样一来,对象之间的耦合度会大大降低,提供高了
系统的维护性。
c.集成其它框架:
Spring可以将其它一些常用的框架集成进来,比如
可以将Quartz,MyBatis等集成进来。
(2)Spring容器
1)Spring容器是什么?
Spring框架的一个核心模块,用于管理对象。
注:
管理对象指的是,spring容器会用我们创建对象,并且建立对象之间的依赖关系。
2)如何启动Spring容器?
step1.导入jar包。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.8.RELEASE</version>
</dependency>
step2.添加配置文件(applicationContext.xml)。
将配置文件添加到main/resources下。
比如 在spring-mvc配置文件里 组件扫描
<context:component-scan base-package="cn.tedu.project.controller" />
配置视图解析器ViewResolver
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置前缀 -->
<property name="prefix" value="/WEB-INF/" />
<!-- 配置后缀 -->
<property name="suffix" value=".jsp" />
<!-- 经过以上配置后, -->
<!-- 当前项目中的jsp文件都应该放在/WEB-INF/下 -->
</bean>
<!-- 注解驱动 -->
<mvc:annotation-driven />
关于spring框架中的注解驱动
1、在springmvc框架中,想要使用mvc,就要使用mvc:annotation-driven/mvc的注解驱动,springmvc工作需要处理器映射器和处理器适配器,使用了这个配置就可以直接使用@Controller,进行web层的注解。
2、在整个项目的流程中,spring对类的实例化,以及类和类之间的关系就需要<context:component-scan/> 组件扫描,使用组件扫描可以扫描指定包下面的注解类,以及成员变量,也就是实例化类,同时完成spring的注入功能。
3、最后一个在spring配置事物的过程中,一般建议的还是使用手动配置事物,因为手动配置可以约定很多方法的前缀,想select,find,get,insert,delete、update等,在开发过程中便于统一所有人的命名方式。
step3.启动Spring容器。
ApplicationContext ac = new ClassPathXmlApplicationContext(“applicationContext.xml”);
3)创建对象
a.方式一 使用无参构造器
step1. 给类添加无参构造器(缺省构造器)。
step2. 在配置文件当中,使用bean元素来进行配置。
step3. 启动容器,调用容器提供的getBean方法。
//通过容器获得对象
Apple ap1 = ac.getBean("ap1",Apple.class);
b.方式二 使用静态工厂方法 (了解)
c.方式三 使用实例工厂方法 (了解)
4)作用域
a.默认情况下,对于某个bean,容器只会创建一个实例。
b.如果要让容器创建多个实例,需要设置bean的作用域。
5)生命周期
spring容器在创建好对象之后,会调用初始化方法,在销毁该对象之前,会调用销毁方法。
<!-- init-method属性: 指定初始化方法 destroy-method属性:指定销毁方法。
注:销毁方法只有当作用域为singleton才有效。
-->
<bean id="mb1" class="basic.MessageBean" init-method="init"
destroy-method="destroy" scope="singleton"/>
6)延迟加载
a.默认情况下,容器启动之后,会将所有作用域为singleton的bean实例化。
b.延迟加载指的是,通过设置lazy-init="true"告诉容器,启动之后不再创建其实例。
<!-- lazy-init属性如果值为true,表示延迟加载。 -->
<bean id="lb1" class="basic.LazyBean" lazy-init="true"/>
(3)IOC和DI
1)IOC是什么? (Inversion Of Controll 控制反转)
对象之间的依赖关系应该由容器来建立。
2)DI是什么? (Dependency Injection 依赖注入)
容器通过调用set方法或者构造器来建立对象之间的依赖关系。
注: IOC是目标,DI是手段。
3)set方法注入
step1. 为类添加set方法。
step2. 在配置文件当中,使用property元素来配置set方法注入。
step3. 启动容器,调用getBean方法。
4)构造器注入
step1. 添加相应的带参的构造器。
step2. 使用元素来配置构造器注入。
<bean id="cpu" class="ioc.Cpu"/>
<!--
constructor-arg元素用来配置构造器注入。
index属性用于指定参数的下标。
ref属性用于指定被注入的bean的id。
-->
<bean id="cp" class="ioc.Computer">
<constructor-arg index="0" ref="cpu"/>
</bean>
step3. 启动容器,调用getBean方法。
4)自动装配 (了解)
a.什么是自动装配?
容器依据某些规则,自动查找符合要求的对象,然后建立对象之间的依赖关系。
注: 容器仍然要调用set方法或者构造器。
b.如何自动装配?
使用autowire属性指定装配的规则:
<bean id="wt1" class="autowire.Waiter"/>
<!-- autowire属性表示让容器自动建立对象之间的依赖关系,有三个值:
byName:以属性名作为bean的id,查找对应的bean,然后调用set方法。
注:如果找不到对应的bean,不会调用set方法。
byType:
以属性类型作为bean的类型,查找对应的bean,然后调用set方法。
注:如果找不到对应的bean,不会调用set方法。如果找到多个bean,会出错。
constructor:类似于byType,只不过是调用构造器来完成 注入。
-->
<bean id="rest" class="autowire.Restaurant" autowire="byType"/>
当使用了自动装配后,由Spring管理的对象时,会自动尝试为各属性注入值,值的来源可以是其它bean,例如:
public class UserService {
public IUserDao userDao;
}
public class UserDao1 implements IUserDao {
}
如果以上2个类都是由Spring管理的,则在创建UserService
对象时,会尝试自动的将UserDao
对象作为其属性值!
自动装配的常用模式有byName
和byType
,前者表示根据名称来装配,即:要求bean id与属性名保持一致,后者表示根据类型来装配,即bean的类型与属性的类型保持一致(允许是接口与实现类的关系,也允许是父子级继承的关系),不过,根据类型装配,要求匹配该类型的对象必须是有且仅有1个,如果有2个,则会抛出异常,无法装配!
5)注入基本类型的值
<bean id="vb" class="value.ValueBean">
<property name="name" value="小包总"/>
<property name="age" value="20"/>
</bean>
6)注入集合类型的值
a.支持四种集合类型的值的注入,分别是List,Set,Properties,Map。
b.注入方式如下:
<property name="interest">
<list>
<value>打猎</value>
<value>看书</value>
<value>编程</value>
<value>编程</value>
</list>
</property>
<property name="city">
<set>
<value>洛阳</value>
<value>金陵</value>
<value>开封</value>
</set>
</property>
<property name="score">
<map>
<entry key="english"
value="59.5"/>
<entry key="math"
value="17"/>
</map>
</property>
<property name="db">
<props>
<prop key="username">tom</prop>
<prop key="pwd">1234</prop>
</props>
</property>
7)引用的方式注入集合类型的值
<!-- 将集合类型的值配置成一个bean -->
<util:list id="interestBean">
<value>打猎</value>
<value>看书</value>
<value>编程</value>
</util:list>
<util:set id="cityBean">
<value>北京</value>
<value>南京</value>
<value>东京</value>
</util:set>
<util:map id="scoreBean">
<entry key="english" value="80"/>
<entry key="math" value="90"/>
</util:map>
<util:properties id="dbBean">
<prop key="username">John</prop>
<prop key="pwd">1234</prop>
</util:properties>
<bean id="vb2" class="value.ValueBean">
<property name="interest"
ref="interestBean"/>
<property name="city"
ref="cityBean"/>
<property name="score"
ref="scoreBean"/>
<property name="db"
ref="dbBean"/>
</bean>
8)读取properties文件的内容
<!-- 读取properties文件的内容。location属性用于指定要读取的文件的位置。
注:classpath:表示依据类路径去查找相应的文件。
-->
<util:properties id="config" location="classpath:config.properties"/>
9)spring表达式
a.spring表达式的作用?
可以用来读取其它bean的属性
2. Spring注解
在Spring中,定义了一系列的注解,可以取代几乎所有的XML配置!
尽管使用注解可以完成此前的许多配置,但是,基于Spring的项目仍需要Spring的配置文件!
2.1. 常用注解
使用注解的方式来创建和管理对象,首先,必须在Spring的配置文件中添加组件扫描:
<!-- 组件扫描 -->
<!-- 仅在组件扫描的包下的类,才会被Spring管理 -->
<!-- 某个类,如果在扫描范围中,且添加了注解,则会被Spring管理 -->
<!-- base-package:扫描的根包 -->
<!-- 根包:父级包,Spring扫描时,会扫描其各层级子包 -->
<!-- 当配置为cn.tedu.spring时 -->
<!-- cn.tedu.spring.dao或cn.tedu.spring.entity这些子包都会被扫描 -->
<context:component-scan base-package="cn.tedu.spring.entity" />
然后,确保需要被管理的类都在以上配置的包中(也可以在其子包中),并且,在类的声明之前添加注解:
@Component
在默认情况下,被管理的类的bean id是与类的名称相同,且首字母小写的!例如类名是User
,则默认的bean id是user
,或类名是UserDao
,则默认的bean id是userDao
。
如果需要自定义bean id,可以在注解中添加bean id:
@Component("bean-id")
与@Component
作用相同的注解还有:
@Controller
@Service
@Repository
其中,@Component
是通用注解,即对任意类都可以添加该注解,@Controller
是对控件器类的注解,@Service
是对业务类的注解,@Repository
是对持久层类的注解。
不过,以上这4种的作用和使用方式完全相同!只是语义不同,即从语法上表达的意义不相同,应该根据类的定位来选取 其中的某个注解!
2.2. 【了解】管理对象的作用域与生命周期
由Spring所管理的对象,默认都是饿汉式单例的,通过@Scope
注解可以配置某个类被Spring管理时,是否是单例的:
@Scope("prototype")
public class ...
常用的配置方式有@Scope("singleton")
和@Scope("prototype")
。
如果需要配置该类最终是否是懒加载的,可以使用@Lazy
注解,当添加了该注解后,就是懒加载模式,即:只有第1次获取对象时,才会创建对象,而在加载Spring配置文件的过程中,并不会把对象创建出来!
关于@Lazy
也可以配置值,例如@Lazy(true)
或@Lazy(false)
。
饿汉式:一开始就已准备好了,随时都有的吃!
懒汉式:不到逼不得已,不干活!
注意:是否懒加载,是建立在单例的基础之上的!如果不是单例的,则懒加载的配置是无效的!
作用域:在多大的范围内是有效的!对于变量/对象而言,作用域就是它存在的时长,即何时创建及何时销毁!由于单例的对象都是static实现的,也就涉及创建时间和销毁时间的问题!而非单例的,作用域与普通的局部变量相同!
简单的懒汉式单例代码(没有解决线程安全问题):
public class King {
private static King king = null;
private King() {
}
public static King getInstance() {
if (king == null) {
king = new King();
}
return king;
}
}
由Spring管理的对象,也存在生命周期问题,毕竟单例模式的类的对象何时创建、何时销毁,是我们无法确定的!为了确保初始化和销毁工作的正常执行,Spring允许在类中自定义初始化方法和销毁方法,使用了@PostConstruct
注解的方法是生命周期初始化方法,会在构造方法之后被自动调用,使用了@PreDestroy
注解的方法是生命周期销毁方法,会在Spring容器销毁并释放资源的前一刻被自动调用。
注意:以上2个方法是在javax包中定义的,使用之前,需要为项目添加Tomcat运行环境,否则无法识别!
注意:以上生命周期方法是建立在单例模式之下的,对于非单例模式而言,以上生命周期方法其实没有意义!