一. 概述

  1. 官网 https://spring.io/
  2. 核心jar包
commons-collections-3.2.jar
commons-logging.jar
spring-aop-4.0.6.RELEASE.jar
spring-beans-4.0.6.RELEASE.jar
spring-context-4.0.6.RELEASE.jar
spring-core-4.0.6.RELEASE.jar
spring-expression-4.0.6.RELEASE.jar
  1. 默认以单例形式管理bean
  • src/beans.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="helloWorld" class="com.bee.HelloWorld"></bean>

</beans>

被管理的类

public class HelloWorld {

public void say(){
System.out.println("Spring4俺来也");
}
}

测试类

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.bee.HelloWorld;

public class Test {

public static void main(String[] args) {
ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");
//强转的方式
//HelloWorld helloWorld=(HelloWorld)ac.getBean("helloWorld");

//非强转的方式
HelloWorld helloWorld=ac.getBean("helloWorld", HelloWorld.class);
helloWorld.say();
}
}

这样就可以让Spring来管理bean。

二. Spring IoC

IoC(控制反转:Inverse of Control),用于解除类之间的耦合,他是Spring架构的核心。IoC体现的是设计模式中的“好莱坞法则:don’t call us, we’ll call you”。

这里的“控制”就是​​new​​对象。在哪个类中new对象,那个类就控制被new的对象。控制反转就是要取消类中的new,把所有获得对象的new都统一收归到Spring框架里来,比如:

ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");

这样就只有一个new,用于生成Spring框架的对象。Spring框架就可以统一管理各个对象,而不是让用户的类来管理对象。用户对类对象的控制权就反转过来交给Spring框架——控制反转。

现在设定一个场景用于解释控制反转:

项目主管Boss安排测试人员Mufasa和Daoba对代码进行测试。用户类是Boss,而类Mufasa和Daoba受Boss管理,Boss类依赖Mufasa和Daoba对象。

  1. 用户类直接控制依赖的对象
public class Mufasa {
public void doTest() {
System.out.println("我不入地狱谁入地狱,一个字——干。");
}
}

public class Daoba {
public void doTest() {
System.out.println("王侯将相宁有种乎,老子就不干,咋地。");
}
}

//Boss类与Mufasa和Daoba对象深度耦合——如果Boss不想要Daoba,还得修改自身的代码再编译。
public class Boss {
public void comeOnBaby() {
Mufasa mufasa = new Mufasa();
mufasa.doTest();
Daoba daoba = new Daoba();
daoba.doTest();
}
}

//测试
public class ClientGo {

public static void main(String[] args) {
Boss boss = new Boss();
boss.comeOnBaby();
}
}

由于用户类直接控制了依赖的对象,所以用户类与依赖对象之间就形成了强耦合——改变依赖关系需要修改源代码。

  1. 使用控制反转
public interface Tester {
void doTest();
}

public class Mufasa implements Tester {
@Override
public void doTest() {
System.out.println("我不入地狱谁入地狱,一个字——干。");
}
}

public class Daoba implements Tester {
@Override
public void doTest() {
System.out.println("王侯将相宁有种乎,老子就不干,咋地。");
}
}

public class Boss {
private Tester tester;
//这里就是Boss的依赖注入(DI)
public void setTester(Tester tester) {
this.tester = tester;
}

public void comeOnBaby() {
tester.doTest();
}
}

//测试
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.bee.beans.Boss;

public class ClientGo {

public static void main(String[] args) {
ApplicationContext appContext = new ClassPathXmlApplicationContext("beans.xml");
Boss boss = (Boss) appContext.getBean("boss");
boss.comeOnBaby();
}
}

控制反转的实现需要借助依赖注入(DI,Dependency Injection)特性。当通过Spring IoC将对象创建出来以后,必然需要对新建对象的属性(对象引用)进行赋值——这个赋值的操作在Spring这里就叫依赖注入。

  1. 把控制权交给Spring框架
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="mufasa" class="com.bee.beans.Mufasa"></bean>

<bean id="daoba" class="com.bee.beans.Daoba"></bean>

<bean id="boss" class="com.bee.beans.Boss">
<property name="tester" ref="mufasa"></property>
</bean>

</beans>

对依赖对象的管理变成Spring框架配置文件中一个bean标签的管理。在配置文件中还可以通过property标签来管理依赖注入——这里Boss方便地完成了对Mufasa的依赖,而剔除了对Daoba的依赖——不用修改自身源代码。

这一切的实现基础是反射。值得关注的是控制反转后看不到用户类的new操作了。

三. Spring DI的常见方式

先定义一个实体bean

public class People {
private int id;
private String name;
private int age;

public People() {
super();
}
public People(int id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "People [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
  1. 属性注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="people" class="com.bee.entity.People">
<property name="id" value="1"></property>
<property name="name" value="穆法沙"></property>
<property name="age" value="8"></property>
</bean>
</beans>
  1. 构造函数注入(通过类型;通过索引;两者兼用)
通过类型
<bean id="people" class="com.bee.entity.People">
<constructor-arg type="int" value="2"></constructor-arg>
<constructor-arg type="String" value="辛巴"></constructor-arg>
<constructor-arg type="int" value="6"></constructor-arg>
</bean>

通过索引
<bean id="people" class="com.bee.entity.People">
<constructor-arg index="0" value="2"></constructor-arg>
<constructor-arg index="1" value="辛巴"></constructor-arg>
<constructor-arg index="2" value="6"></constructor-arg>
</bean>

两者兼用
<bean id="people" class="com.bee.entity.People">
<constructor-arg index="0" type="int" value="2"></constructor-arg>
<constructor-arg index="1" type="String" value="辛巴"></constructor-arg>
<constructor-arg index="2" type="int" value="6"></constructor-arg>
</bean>
  1. 工厂方法注入(非静态工厂;静态工厂)
  • 非静态工厂
public class PeopleFactory {
public People createPeople(){
People p=new People();
p.setId(3);
p.setName("刀疤");
p.setAge(10);
return p;
}
}

配置文件beans.xml

<bean id="peopleFactory" class="com.bee.factory.PeopleFactory"></bean>
<bean id="people" factory-bean="peopleFactory" factory-method="createPeople"></bean>
  • 静态工厂
public class PeopleFactory {
public static People createPeople(){
return new People(4, "波波", 8);
}
}

配置文件beans.xml(静态方法是跟着类class走的)

<bean id="peopleFactory" class="com.bee.factory.PeopleFactory"></bean>
<bean id="people" class="com.bee.factory.PeopleFactory" factory-method="createPeople"></bean>

四. Spring注入参数

实体bean

public class People {
private int id;
private String name;
private int age;
private Dog dog;
private List<String> hobbies=new ArrayList<String>();
private Set<String> loves=new HashSet<String>();
private Map<String,String> works=new HashMap<String,String>();
private Properties addresses=new Properties();

public People() {
}
public People(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public Set<String> getLoves() {
return loves;
}
public void setLoves(Set<String> loves) {
this.loves = loves;
}
public List<String> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
public Map<String, String> getWorks() {
return works;
}
public void setWorks(Map<String, String> works) {
this.works = works;
}
public Properties getAddresses() {
return addresses;
}
public void setAddresses(Properties addresses) {
this.addresses = addresses;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "People [id=" + id + ", name=" + name + ", age=" + age
+ ", dog=" + dog + ", hobbies=" + hobbies + ", loves=" + loves
+ ", works=" + works + ", addresses=" + addresses + "]";
}
}

public class Dog {
private String name;

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

参数注入的例子

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

1. 基本类型值
<bean id="people1" class="com.bee.entity.People">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="age" value="11"></property>
</bean>

<bean id="dog1" class="com.bee.entity.Dog">
<property name="name" value="Jack"></property>
</bean>

2. 注入bean
<bean id="people2" class="com.bee.entity.People">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="age" value="11"></property>
<property name="dog" ref="dog1"></property>
</bean>

3. 内部bean
<bean id="people3" class="com.bee.entity.People">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="age" value="11"></property>
<property name="dog">
<bean class="com.bee.entity.Dog">
<property name="name" value="Tom"></property>
</bean>
</property>
</bean>

4. null值
<bean id="people4" class="com.bee.entity.People">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="age" value="11"></property>
<property name="dog">
<null></null>
</property>
</bean>

5. 级联属性
<bean id="people5" class="com.bee.entity.People">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="age" value="11"></property>
<property name="dog.name" value="Jack2"></property>
</bean>

6. 集合类型属性
<bean id="people6" class="com.bee.entity.People">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="age" value="11"></property>
<property name="dog" ref="dog1"></property>
<property name="hobbies">
<list>
<value>唱歌</value>
<value>跳舞</value>
</list>
</property>
<property name="loves">
<set>
<value>唱歌2</value>
<value>跳舞2</value>
</set>
</property>
<property name="works">
<map>
<entry>
<key><value>上午</value></key>
<value>写代码</value>
</entry>
<entry>
<key><value>下午</value></key>
<value>测试代码</value>
</entry>
</map>
</property>
<property name="addresses">
<props>
<prop key="address1">aaaaa</prop>
<prop key="address2">bbbbb</prop>
</props>
</property>
</bean>

</beans>