I. Spring框架
Bean的实例化
1. Spring概述
1. Spring介绍 —— spring是什么
Spring是一个开源的轻量级应用开发框架,其目的是用于简化企业应用程序的开发,降低侵入性。
Spring提供的IOC和AOP功能,可以将组件的耦合度降至最低,即解耦,便于系统的维护和升级。
Spring为系统提供一个整体的解决方案,开发者可以利用它本身提供的功能外,也可以与第三方框架和技术整合应用,可以自由选择哪种技术进行开发。
Spring的本质是管理软件中的对象,即创建对象和维护对象之间的关系。
2. Spring容器
在Spring中,任何的Java类和JavaBean都被当成Bean对象处理,这些Bean是通过容器管理和使用
Spring容器有BeanFactory和ApplicationContext两种类型
Spring容器的实例化
ApplicationContext继承自BeanFactory接口,拥有更多的企业级方法(推荐)
加载工程classpath下的配置文件实例化
String xml = "配置文件路径";
ApplicationContext ac = new ClassPathXmlApplicationContext(xml);
Spring容器的使用
从本质上讲,BeanFactory和ApplicationContext仅仅是一个维护Bean定义以及相互依赖关系的高级工厂接口,通过容器访问Bean定义。
首先在容器配置文件spring.xml中添加Bean定义
<beanid="标识符" class="Bean类型(包名+类名)" />
<bean id="gregorianCalendar" class="java.util.GregorianCalendar"></bean> |
然后在创建容器对象后,调用getBean()方法获取Bean的实例
getBean("标识符")
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml"); Calendar c1 = (Calendar) ac.getBean("gregorianCalendar"); //get到的是object类型,需要进行对象强转 System.out.println(c1); |
2. Bean的实例化
Spring容器创建Bean对象的方式有以下三种:
1) 用构造器的方式来实例化
<!-- 通过构造器实例化Bean --> <!-- 会自动调用无参构造器创建对象 --> <bean id="gregorianCalendar" class="java.util.GregorianCalendar"></bean> |
2) 静态工厂方法实例化
<!-- 通过静态工厂方法实例化Bean --> <!-- factory-method属性用于指定工厂中创建Bean对象的方法 --> <bean id="calendar" class="java.util.Calendar" factory-method="getInstance"></bean> |
3) 实例工厂方法实例化
<!-- 通过实例工厂方法实例化Bean --> <!-- factory-bean属性用于指定工厂Bean对象 --> <bean id="date" factory-method="getTime" factory-bean="gregorianCalendar"></bean> |
Bean的命名
在Spring的容器中,每个Bean都需要有名字(即标识符),此名字可以用<bean>元素的id属性或者name属性指定
3. Bean的作用域
Spring容器在实例化Bean时,可以创建以下作用域的Bean对象
singleton:在Spring容器中一个Bean定义对应一个实例对象,默认项
prototype: 一个Bean定义对应多个实例对象
request:在一次Http请求中,一个Bean定义对应一个实例对象
session:在一次HttpSession中,一个Bean定义对应一个实例对象
Bean的作用域,可以通过<bean>定义的scope属性来指定
<!-- Bean的作用域 --> <bean id="gregorianCalendarOne" class="java.util.GregorianCalendar" scope="singleton"></bean> <bean id="gregorianCalendarTwo" class="java.util.GregorianCalendar" scope="prototype"></bean> |
4. Bean的生命周期
指定初始化回调方法
<bean int-method=" ">
指定销毁回调方法,仅适用于singleton模式的Bean
<bean destory-method=" "/>
在<beans>元素中的default-init-mehod属性,可以为容器中的<bean>指定初始化回调方法,也可以通过default-destroy-method属性为容器中的<bean>指定销毁回调方法
<!--bean的生命周期--> <bean id="exampleBean" scope="singleton" init-method="init" class="com.xms.entity.ExampleBean" destroy-method="destroy" ></bean>
AbstractApplicationContext aac = new ClassPathXmlApplicationContext("spring.xml"); ExampleBean exampleBean = ac.getBean("exampleBean",ExampleBean.class); aac.close(); //close容器时才会调用destroy方法 |
5. Bean的延迟实例化
默认行为是在容器实例化的同时将单例模式的Bean提前进行实例化
延迟实例化的操作:在<bean>声明时指定其属性 lazy-init="true"
一个延迟实例化的Bean将在第一次被用到时实例化
注意:仅适用于单例模式
在<beans>元素中的default-lazy-init属性,可以为容器中的<bean>指定延迟实例化特性
<bean id="exampleBean" scope="singleton" init-method="init" class="com.xms.entity.ExampleBean" destroy-method="destroy" lazy-init="true"></bean> |
6. 基于注解的组件扫描
什么是组件扫描?
指定一个包路径,Spring会自动扫描此包及其子包中所有的组件类,当发现组件类定义前有特定的注解标记时,就将此组件纳入到Spring容器, 等价于原有的XML配置中的<bean>定义
组件扫描可以替代大量XML配置的<bean>定义
指定扫描路径,使用组件扫描,首先需要在XML配置中指定扫描父级package路径
<context:component-scan base-package="com.xms"/>
<!-- 开启注解扫描 --> <context:component-scan base-package="com.xms"></context:component-scan> |
容器会自动扫描指定包及其子包下所有的组件类,如果此组件类定义前有特定的注解标记,则会实例化为Bean对象。
自动扫描的注解标记
@Component 通用注解
@Repository 持久层组件注解
@Service 业务层组件注解
@Controller 控制层组件注解
自动扫描组件的命名
当一个组件在扫描过程中被检测到时,会生成一个默认的id值,默认id为小写开头的类名,也可以在注解标记中自定义id
指定组件的作用域
通常受Spring容器管理的组件,默认作用域是“singleton”,如果需要其他的作用域可以使用@Scope注解,只要在注解中提供作用域的名称即可
指定初始化和销毁回调方法
@PostConstruct 和 @PreDestroy注解标记分别用于指定初始化和销毁回调方法
注解类型中默认取消了延迟加载
@Component("example") //此处注解可以指定id @Scope("singleton") public class ExampleBean {
public ExampleBean(){ System.out.println("实例化ExampleBean:"+this); }
@PostConstruct //初始化方法 public void init(){ System.out.println("初始化ExampleBean"); }
@PreDestroy //销毁方法 public void destroy(){ System.out.println("销毁ExampleBean"); } } |
Bean参数值的注入
1. Spring IOC
IOC全称,被翻译为控制翻转
IOC是指程序中对象的获取方式发生反转,由最初的new的方式创建,转变为由第三方框架创建,注入(DI),可以降低对象之间的耦合度
Spring容器采用DI方式实现IoC控制,IOC是Spring框架的基础和核心
DI全称是DependencyInjection,被翻译成依赖注入
DI的基本原理是将一起工作具有关系的对象,通过方法参数传入建立关系,因此容器的工作就是创建Bean时注入依赖关系
IOC是一种思想,而DI是实现IOC的主要技术途径
DI主要有两种注入方式,即Setter注入和构造器注入
1) Setter注入
通过调用无参构造器或无参static工厂方法实例化Bean之后
调用此Bean的Setter方法,即可实现setter方式的注入
<!-- Setter注入 --> <bean id="computer" class="com.xms.entity.Computer" > <property name="cpu" value="Inter"></property> <property name="mainboard" > <value>华硕</value> </property> <property name="memory" value="金士顿"></property> <property name="caliche" value="希捷"></property> </bean> |
2) 构造器注入
通过调用带参数的构造器来实现,容器在Bean被实例化时候,根据参数类型执行相应的构造器
<!-- 构造器注入--> <bean id="mobilePhone" class="com.xms.entity.MobilePhone"> <!-- 默认是String类型的构造器,如果要其他的参数,需要设定type,如 type="java.lang.Integer" --> <constructor-arg index="0" value="Inter" type="java.lang.String"></constructor-arg> <constructor-arg index="1" value="4G" type="java.lang.String"></constructor-arg> </bean> |
自动装配
Spring容器可以自动装配(autowire)相互协作Bean之间的关联关系,autowire可以针对单个Bean进行设置,方便之处在于减少xml的注入配置
在配置文件中,可以在<bean>元素中使用autowire属性来指定自动装配的规则,
一共有四种类型值,
no:禁用自动装配,默认值
byName:根据属性名自动装配,此选项将检查容器,根据名字查找与属性名一致的Bean,然后将其与属性自动装配(setter注入)
byType:如果容器中存在一个与指定属性类型相同的Bean,则将与此属性自动装配(setter注入)
constructor:与byType方式类似,不同之处在于它应用于构造器参数的方式
<!-- 自动装配 --> <bean id="student" autowire="constructor" class="com.xms.entity.Student"></bean> |
2. 参数值注入
1) 注入基本值
<value> 元素可以通过字符串指定属性或构造器参数的值
容器将字符串java.lang.String类型转换为实际的属性或参数类型
然后给Bean对象注入
<!-- Setter注入 --> <bean id="messageBeanOne" class="com.xms.entity.MessageBean" > <!-- 基本值 --> <!-- setter注入 --> <property name="name"> <value>张三</value> </property> <property name="age" value="18"></property> </bean> |
2) 注入bean对象
注入外部Bean(引用方式,方便重用)
<!-- Setter注入 --> <bean id="messageBeanOne" class="com.xms.entity.MessageBean" > <!-- Bean对象 --> <property name="user" ref="user"></property> </bean> <bean id="user" class="com.xms.entity.User"> <property name="name" value="李四"></property> <property name="age" value="18"></property> </bean> |
3) 注入集合
通过<list>,<set>,<map>,<props>元素可以定义和设置与Java类型中对应的List,set,Map及Properties的属性
List,Set,Map及Properties都可以采用引入方式注入<util:list>,<util:set>
<util:map>,<util:properties>
<!-- Setter注入 --> <bean id="messageBeanOne" class="com.xms.entity.MessageBean" > <!-- List --> <property name="languages"> <list> <value>C++</value> <value>Java</value> <value>PHP</value> <value>Python</value> </list> </property>
<!-- Set --> <property name="cities"> <set> <value>北京</value> <value>西藏</value> <value>云南</value> <value>青岛</value> </set> </property>
<!-- Map --> <property name="scores"> <map> <entry key="JSD1706" value="95"></entry> <entry key="JSD1704" value="100"></entry> </map> </property>
<!-- Properties --> <property name="ps"> <props> <prop key="user">root</prop> <prop key="password">1234</prop> </props> </property> </bean> |
<!-- 采用引用方式注入集合 --> <!-- 声明集合 --> <util:list id="list"> <value>C++</value> <value>Java</value> <value>PHP</value> <value>Python</value> </util:list>
<util:set id="set"> <value>北京</value> <value>西藏</value> <value>云南</value> <value>青岛</value> </util:set>
<util:map id="map"> <entry key="JSD1706" value="95"></entry> <entry key="JSD1704" value="100"></entry> </util:map>
<util:properties id="ps"> <prop key="user">root</prop> <prop key="password">1234</prop> </util:properties>
<bean id="messageBeanTwo" class="com.xms.entity.MessageBean"> <!-- 基本值 --> <!-- setter注入 --> <property name="name"> <value>张三</value> </property>
<property name="age" value="18"></property>
<!-- Bean对象 --> <property name="user" ref="user"></property>
<!-- 集合 --> <property name="languages" ref="list"></property> <property name="cities" ref="set"></property> <property name="scores" ref="map"></property> <property name="ps" ref="ps"></property> </bean> |
4) 注入spring表达式
Spring表达式,和El表达式在语法上很相似,可以读取一个
<!-- 加载属性配置文件 --> <util:properties id="ds" location="classpath:db.properties"></util:properties>
<bean id="demoBean" class="com.xms.entity.DemoBean"> <property name="name" value="#{user.name}"></property> <property name="language" value="#{list[0]}"></property> <property name="city" value="#{messageBeanOne.cities[0]}"></property> <property name="score" value="#{map.JSD1704}"></property> <property name="pageSize" value="#{ds.pageSize}"></property> </bean> |
5) 注入null或字符串
Spring将属性的空参数当做空String
<bean>
<property name="name" value=""/>
</bean>
如果需要注入NULL值,可以使用<null>元素
<bean>
<property name="name">
<null/>
</property>
</bean>
3. 基于注解依赖注入
3. 基于注解依赖注入
具有依赖关系的Bean对象,可以使用以下任意一种注解实现
@Autowired /@Qualifer
可以处理构造器注入和setter注入
Autowired写在构造器或set方法前,声明需要为其注入Bean,@Qualifer写在参数前面,声明需要注入的Bean的id值
@Component public class Programmer {
private Computer computer;
public Programmer(){}
@Autowired public Programmer(@Qualifier("computer")Computer computer){ this.computer = computer; }
public Computer getComputer(){ return computer; } } |
@Autowired也可以写在属性上,作用和写在set方法上类似,但是只会执行一行代码(赋值)
@Component public class Student {
@Autowired @Qualifier("computer") private Computer computer;
public Computer getComputer() { return computer; }
public void setComputer(Computer computer) { System.out.println("我是Computer"); this.computer = computer; } } |
注意:注入对象是单例时,@Qualifer可省略,此时Spring按照类型匹配参数
@Resource
只能处理Setter注入
注意:注入对象是单例时,(name=“标识符”)可省略,此时Spring按照类型匹配参数
@Component public class Manager {
private Computer computer;
@Resource public void setComputer(Computer computer) { System.out.println("我是Manager"); this.computer = computer; }
public Computer getComputer() { return computer; } } |
@Resource也可以写在属性上,作用和写在set方法上类似,但是只会执行一行代码(赋值代码)
@Inject/@Named
和@Autowired/@Qualifer用法一致,需要额外导包
@Inject注解标记时Spring3.0 开始增添的对JSR-330标准的支持,需要添加JSR-330的jar包,javax.inject-1.jar
@Inject/@Named注解用法和@Autowired/@Qualifer一致,其中@Inject等价于@Autowired,@Named等价于@Qualifer
注入基本值或Spring表达式值
@Value注解可以注入基本值或Spring表达式值
@Value("Inter") private String cpu;
@Value("华硕") private String mainboard;//主板 private String memory;//内存 private String caliche;//硬盘 |