SpringIoC容器
通过上一篇的描述我们对Spring框架有了一定的了解:
Spring框架实则就是IoC(控制反转)容器,同时也是实现了DI(依赖注入)
IoC容器构建
SpringIoC的构建方式:
(1)基于XML配置的方式
(2)基于Java Config的配置注解方式(主要通过Configuration和Bean注解及其他注解后续再使用)
(3)基于Goovy脚本的配置方式(这个需要我们对Goovy语言有一定的了解)
方式1:XML方式配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:contex="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="exampleBean" class="com.dyy.springcore.ExampleBean">
</beans>
使用方式
ApplicationContext context = new ClassPathXmlApplicationContext("application-content.xml");
ExampleBean exampleBean = (ExampleBean) context.getBean("exampleBean");
方式2: Java Config方式配置
package com.dyy.springcore;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
@Configurable
public class IoCJavaConfigApplication {
@Bean
public String hello(){
return "hello";
}
}
使用方式
AnnotationConfigApplicationContext context1 = new AnnotationConfigApplicationContext(IoCJavaConfigApplication.class);
String hello = context1.getBean(String.class);
Bean的实例化
在JavaSE中我们可以使用三种方式创建实例化对象:new()、反射、反序列化
在XML配置中完成实例化同样有三种方式:构造方法实例化、静态工厂方法实例化、实例工厂方法实例化
构造方法实例化
public class ExampleBean {
public String currentDate(){
return new SimpleDateFormat().format(new Date());
}
}
bean id="exampleBean" class="com.dyy.springcore.ExampleBean"/>
ApplicationContext context = new ClassPathXmlApplicationContext("application-content.xml");
ExampleBean exampleBean = (ExampleBean) context.getBean("exampleBean");
以上为使用默认构造函数进行bean的转配,当我们含有有参构造时,则默认构造函数失效,
则我们需要使用<constructor-args>元素来进行配置,如下例所示:
public class ExampleBean2 {
private final String name;
public ExampleBean2(String name) {
this.name = name;
}
public String currentDate(){
return new SimpleDateFormat().format(new Date());
}
public String getName(){
return name;
}
@Override
public String toString() {
return "ExampleBean2{" +
"name='" + name + '\'' +
'}';
}
}
<bean id="exampleBean2" class="com.dyy.springcore.ExampleBean2">
<constructor-arg value="dyy"/>
</bean>
静态工厂方法实例化
静态工厂方法实例化即通过哟个类的静态(工厂)方法来创建bean (和我们所学到的单例设计模式有点相似)
我们可以在对象返回之前来进行属性的设置,这样可以完成对象的创建。
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService(){}
public static ClientService creatInstance(){
return clientService;
}
}
<bean id="clientService" class="com.dyy.springcore.ClientService" factory-method="creatInstance"/>
实例工厂方法实例化
实例工厂方法和静态方法比较相似,区别在于实例工厂方法是通过已经在容器中的Bean通过其方法实例化一个新的Bean
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService(){}
public static ClientService creatInstance(){
return clientService;
}
}
<bean id="clientServerLocater" class="com.dyy.springcore.DefaultClientServerLocater"/>
<bean id="clientService2" factory-bean="clientServerLocater" factory-method="getClientService"/>
若含有多个多个实例工厂方法时,可以通过同样的方式进行bean的配置。
Bean的依赖装配
构造方法的参数装配
在Spring中,可以“通过构造方法自动装配”,实际上是按照构造函数的参数类型以及构造函数的参数顺序自动进行装配的。
即一个bean的参数类型与其他bean的构造器参数的数据类型相同,则会自动进行装配,
若装配过程中构造方法的参数存在歧义,则我们需要指定类型,位置或参数名来告知Spring如何进行装配
构造方法的装配方式
public class Bar {
}
public class Baz {
}
public class Foo {
private final Bar bar;
private final Baz baz;
public Foo(Bar bar, Baz baz) {
this.bar = bar;
this.baz = baz;
}
@Override
public String toString() {
return "Foo{" +
"bar=" + bar +
", baz=" + baz +
'}';
}
}
public class ExampleBean3 {
private final String name;
private final int id;
public ExampleBean3(String name, int id) {
this.name = name;
this.id = id;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "ExampleBean3{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}
Bean的引用
<bean id="baz" class="com.dyy.springcore.Baz"/>
<bean class="com.dyy.springcore.Bar" id="bar"/>
<bean id="foo" class="com.dyy.springcore.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
</bean>
根据参数类型进行装配
<bean id="foo2" class="com.dyy.springcore.Foo">
<constructor-arg type="com.dyy.springcore.Baz" ref="baz"/>
<constructor-arg type="com.dyy.springcore.Bar" ref="bar"/>
</bean>
<bean id="bean32" class="com.dyy.springcore.ExampleBean3">
<constructor-arg type="java.lang.String" value="dyy"/>
<constructor-arg type="int" value="201512"/>
</bean>
根据参数位置进行装配
<bean id="bean3" class="com.dyy.springcore.ExampleBean3">
<constructor-arg index="0" value="dyy"/>
<constructor-arg index="1" value="201512"/>
</bean>
根据参数名进行装配
<bean id="bean33" class="com.dyy.springcore.ExampleBean3">
<constructor-arg name="id" value="201412"/>
<constructor-arg name="name" value="lms"/>
</bean>
我们很少使用参数名来查找构造方法中的参数,因为具有特殊的限制,
需要我们在开启编译的时进行参数数名保留的设置。
jdk1.8之前使用@ConstructorProperties注解
jdk1.8之后再编译时添加-parameters确保编译之后保留参数名
setter方法的装配方式
容器在调用无参构造方法或者工厂方法实例化Bean后,就调用setter方法来进行属性的装配
public interface Shape {
}
public class Circle implements Shape{
}
public class ComplexShape {
private Shape shape;
public void setShape(Shape shape) {
this.shape = shape;
}
public Shape getShape() {
return shape;
}
@Override
public String toString() {
return "ComplexShape{" +
"shape=" + shape +
'}';
}
}
<bean id="circle" class="com.dyy.springcore.Circle"/>
<bean id="complexShape" class="com.dyy.springcore.ComplexShape">
<property name="shape" ref="circle"/>
</bean>
依赖和配置的详解
直接赋值
直接赋值主要针对基本数据类型和String类型,我们可以在配置properties元素和value属性时用来指定属性或构造方法参数的赋值
step1:
我们引入common-dbcp2开源的数据库连接池库,
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.1.1</version>
</dependency>
step2:
并在配置文件中描述创建数据源(BasicDataSource)对象的方式。
<bean id="basicDataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/memo"/>
<property name="username" value="root"/>
<property name="password" value="100521"/>
<property name="maxTotal" value="100"/>
</bean>
idref和ref元素
元素名 | 装配目标 | 是否验证 |
---|
idref | id而非bean的实例 | 使用idref容器在部署时验证该名称bean是否真实存在(即和value一样,只是将某个字符串装配到属性或者构造函数中,只不过装配的是某个Bean定义的id属性值) |
ref | 将目标定义的实例装配到属性或者构造方法中 | 不进行验证 |
<bean id="config" class="com.dyy.springcore.IdRefConfig">
<constructor-arg>
<idref bean="bar"/>
</constructor-arg>
</bean>
内部bean
一个 <bean/> 元素定义在 <property/> 和 <constructor-arg/> 元素中我们称之为内部Bean
<bean id="foo3" class="com.dyy.springcore.Foo">
<constructor-arg>
<bean class="com.dyy.springcore.Bar"/>
</constructor-arg>
<constructor-arg>
<bean class="com.dyy.springcore.Baz"/>
</constructor-arg>
</bean>
其他相关操作
Collection
使用 <list/>, <set/>, <map/>, <props/> 元素可以设置Java集合类型(比如:List,Set,Map,Properties)的属性和参数。
public class ComplexObject {
private Properties properties;
private List<Object> list;
private Set set;
private Map<Integer,Object> map;
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public List<Object> getList() {
return list;
}
public void setList(List<Object> list) {
this.list = list;
}
public Set getSet() {
return set;
}
public void setSet(Set set) {
this.set = set;
}
public Map<Integer, Object> getMap() {
return map;
}
public void setMap(Map<Integer, Object> map) {
this.map = map;
}
@Override
public String toString() {
return "ComplexObject{" +
"properties=" + properties +
", list=" + list +
", set=" + set +
", map=" + map +
'}';
}
}
<bean id="complexObject" class="com.dyy.springcore.ComplexObject">
<property name="properties">
<props>
<prop key="dyy">dyy@qq.com</prop>
<prop key="xl">xl@qq.com</prop>
</props>
</property>
<property name="list">
<list>
<value>zhangsan</value>
<value>18</value>
<ref bean="foo3"/>
</list>
</property>
<property name="set">
<set>
<value type="java.lang.String">zhangsan</value>
<value>20</value>
<value>js</value>
</set>
</property>
<property name="map">
<map>
<entry key="2014" value="lemon"/>
<entry key="10" value-ref="foo"/>
</map>
</property>
</bean>
在使用集合元素时如Map的key和value,集合的value可以使用以下元素:
bean | ref | idref | list | set | map | props | value | null
Null和空字符串
我们使用<null/>元素来进行空值的处理
public class ExampleBean4 {
private String name;
private String id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public String toString() {
return "ExampleBean3{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}
<bean id="bean4" class="com.dyy.springcore.ExampleBean4">
<property name="name" value="dyy"/>
<property name="id">
<null/>
</property>
</bean>