Spring 是一种轻量级开发框架,旨在提高开发人员的开发效率以及系统的可维护性。
我们一般说 Spring 框架指的都是 Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发。
Spring Core: 基础,可以说 Spring 其他所有的功能都需要依赖于该类库。主要提供 IoC 依赖注入功能。
Spring Aspects : 该模块为与AspectJ的集成提供支持。
Spring AOP :提供了面向切面的编程实现。
Spring JDBC : Java数据库连接。
Spring JMS :Java消息服务。
Spring ORM : 用于支持Hibernate等ORM工具。
Spring Web : 为创建Web应用程序提供支持。
Spring Test : 提供了对 JUnit 和 TestNG 测试的支持。
IOC理解
IoC(Inverse of Control:控制反转)是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由Spring框架来管理。IoC 在其他语言中也有应用,并非 Spring 特有。 IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。
将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。 IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。 在实际项目中一个 Service 类可能有几百甚至上千个类作为它的底层,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。
总的来说就是“解耦”——解除了“开发人员”与“对象管理”之间的耦合,提高了开发效率。
Spring环境搭建
首先需要导入依赖的jar包,或者maven配置依赖,四个核心包和一个日志包:
然后需要在src下新建applicationContext.xml,applicationContext.xml 配置的信息最终存储到了AppliationContext 容器中。
<?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">
<!-- id表示获取到对象标识
class 创建哪个类的对象
-->
<bean id="peo" class="com.test.pojo.People"/>
</beans>
spring 配置文件是基于schema的,schema文件的类型是xsd,xsd文件用来描述一组xml文件需要遵守的规则。
通过<bean>
标签创建需要Spring管理的对象。
<bean id="peo" class="com.test.pojo.People"/>
其中属性id表示获取到对象标识,属性class表示创建哪个类的对象。
这样就已经可以使用Spring来创建对象了:
package com.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.test.pojo.People;
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
People people = ac.getBean("peo",People.class);
System.out.println(people);
}
}
People类如下:
package com.test.pojo;
public class People {
private int id;
private String name;
public People() {
super();
System.out.println("执行构造方法");
}
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;
}
@Override
public String toString() {
return "People [id=" + id + ", name=" + name + "]";
}
}
不管是程序员手动创建对象,还是Spring创建对象,都是需要通过构造方法来创建。由于我们只创建了对象,并没有给对象属性赋值,所以创建的对象都是默认值,即id默认值为0,String类型的name默认值为null。
在Spring中,<bean>
标签对应的对象默认是单例的,当Spring加载applicationContext.xml文件的的时候便会自动创建<bean>
标签对应的单例对象,之后的使用过程中取出,不管取出使用多少次都是单例对象。
例如,我们把getBean方法注释掉,只保留一行加载applicationContext.xml文件的代码:
package com.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.test.pojo.People;
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//People people = ac.getBean("peo",People.class);
//System.out.println(people);
}
}
可以发现,依然执行了构造方法创建了对象,随后我们可以getBean两次,再比较一下它们的地址是否一样:
package com.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.test.pojo.People;
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
People people = ac.getBean("peo",People.class);
System.out.println(people);
People people2 = ac.getBean("peo",People.class);
System.out.println(people2);
System.out.println(people == people);
}
}
“==”判断为true说明两个对象是同一个。
Spring创建对象的三种方式
Spring创建对象有三种创建方式:前面那种方式便是直接通过构造方法创建,另外还有通过实例工厂和静态工厂创建的方式。
直接通过构造方法创建
前面的例子中,Spring创建对象走的是唯一的无参构造方法,在类中可能不止一个构造方法,可能还会有参数不同的有参构造方法,这样我们就需要在<bean>
标签中指定参数,例如:
<bean id="peo" class="com.test.pojo.People">
<!-- ref引用另一个bean value 基本数据类型或String等 -->
<constructor-arg index="0" name="id" type="int" value="123"></constructor-arg>
<constructor-arg index="1" name="name" type="java.lang.String" value="张三"></constructor-arg>
</bean>
<constructor-arg>
标签表示的是构造方法的参数,index属性用于表示参数的顺序,type用于表示参数的数据类型,value表示需要传入的参数值,name属性表示参数名。
People类如下;
package com.test.pojo;
public class People {
private int id;
private String name;
public People() {
super();
System.out.println("执行构造方法");
}
public People(int id, String name) {
super();
this.id = id;
this.name = name;
System.out.println("执行有参构造");
}
public People(Integer id, String name) {
super();
this.id = id;
this.name = name;
System.out.println("执行有参构造Integer");
}
public People(String name,int id) {
super();
this.id = id;
this.name = name;
System.out.println("执行有参构造1111111");
}
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;
}
@Override
public String toString() {
return "People [id=" + id + ", name=" + name + "]";
}
}
可见走的是第一个构造方法,即标签中配置的参数类型和顺序对应着构造方法的参数类型和顺序。
如果设定的条件匹配多个构造方法则会执行最后的构造方法。
例如,我们去掉<bean>
标签中<constructor-arg>
的index属性和type属性,那么满足的构造方法可以是People(int id, String name)和public People(String name,int id),至于执行哪个构造方法取决于它们在类中的位置,默认会执行最后一个符合的构造方法。
People(int id, String name)在最后:
public People(String name,int id)在最后:
通过实例工厂创建
通过实例工厂创建对象需要先构造实例工厂,再生产对象。
package com.test.pojo;
public class PeopleFactory {
public static People newInstance(){
return new People(1,"测试");
}
}
然后在applicationContext.xml中配置工厂对象和需要创建的对象:
这就可以通过实例工厂获取People对象了:
package com.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.test.pojo.People;
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
People people = ac.getBean("peo1",People.class);
System.out.println(people);
}
}
通过静态工厂创建
通过静态工厂创建对象只需要将上面实例工厂的newInstance方法用static修饰即可,同时在applicationContext.xml中配置工厂,不需要再配置被创建的对象了。
package com.test.pojo;
public class PeopleFactory {
public static People newInstance(){
return new People(1,"测试");
}
}
<bean id="peo2" class="com.test.pojo.PeopleFactory" factory-method="newInstance"></bean>
给Bean的属性赋值(注入)
Spring中给Bean的属性赋值的操作一般叫做“注入”,一般有两种注入方式:通过构造方法注入和通过设值注入(set方法)。
通过构造方法注入就是前面通过带参数的构造方法创建对象的方式。
通过设值注入需要在<bean>
标签中使用<property>
标签。
基本数据类型或String
如果需要注入的属性是基本数据类型或String,则可以直接使用<property>
标签中的name和value属性,或者使用子标签<value>
。
等效于:
<bean id="peo" class="com.bjsxt.pojo.People">
<property name="id">
<value>456</value>
</property>
<property name="name">
<value>zhangsan</value>
</property>
</bean>
Set集合
如果属性是Set集合,则需要在<property>
中使用<set>
标签,然后再在子标签<value>
中设置每个元素的值。
<property name="sets">
<set>
<value>1</value>
<value>2</value>
<value>3</value>
<value>4</value>
</set>
</property>
List<?>集合
如果属性是List<?>则需要在<property>
标签中使用子标签<list>
,然后再在子标签<value>
中设置每个元素的值。
<property name="list">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</property>
如果list中只有一个值,可以直接在标签设值。
<property name="list" value="1"></property>
数组
如果是一维数组:
<property name="strs" >
<array>
<value>1</value>
<value>2</value>
<value>3</value>
</array>
</property>
如果是多维数组:
<property name="strs" >
<array>
<array>
<value>1</value>
<value>2</value>
<value>3</value>
</array>
<array>
<value>4</value>
<value>5</value>
<value>6</value>
</array>
</array>
</property>
Map
如果属性是map,则需要使用<map>
标签,并使用<entry>
标签设置键值对。
<property name="map">
<map>
<entry key="a" value="b" ></entry>
<entry key="c" value="d" ></entry>
</map>
</property>
我们创建一个包含上述所有类型属性的People类来测试一下:
package com.test.pojo;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class People {
private int id;
private String name;
private Set<String> sets;
private List<String> list;
private String [] strs;
private Map<String,String> map;
@Override
public String toString() {
return "People [id=" + id + ", name=" + name + ", sets=" + sets + ", list=" + list + ", strs="
+ Arrays.toString(strs) + ", map=" + map + "]";
}
public Map<String, String> getMap() {
return map;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public String[] getStrs() {
return strs;
}
public void setStrs(String[] strs) {
this.strs = strs;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public Set<String> getSets() {
return sets;
}
public void setSets(Set<String> sets) {
this.sets = sets;
}
public People() {
super();
System.out.println("执行构造方法");
}
public People(int id, String name) {
super();
this.id = id;
this.name = name;
System.out.println("执行有参构造");
}
public People(Integer id, String name) {
super();
this.id = id;
this.name = name;
System.out.println("执行有参构造Integer");
}
public People(String name,int id) {
super();
this.id = id;
this.name = name;
System.out.println("执行有参构造1111111");
}
public int getId() {
return id;
}
public void setId(int id) {
System.out.println("执行setId");
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("执行setName");
this.name = name;
}
}
配置文件applicationContext.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="peo" class="com.test.pojo.People">
<property name="id">
<value>456</value>
</property>
<property name="name">
<value>zhangsan</value>
</property>
<property name="sets">
<set>
<value>1</value>
<value>2</value>
<value>3</value>
<value>4</value>
</set>
</property>
<property name="list" value="1"></property>
<property name="strs" >
<array>
<value>1</value>
<value>2</value>
<value>3</value>
</array>
</property>
<property name="map">
<map>
<entry key="a" value="b" >
</entry>
<entry key="c" value="d" >
</entry>
</map>
</property>
</bean>
</beans>
测试代码:
package com.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.test.pojo.People;
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
People people = ac.getBean("peo",People.class);
System.out.println(people);
}
}
依赖注入(DI)
依赖注入(Dependency Injection)简称“DI”,如果一个类需要依赖另一个类的对象时,需要在<property>
标签中使用ref属性引用另外一个<bean>
标签的id属性。
<bean id="peo" class="com.test.pojo.People">
<property name="desk" ref="desk"></property>
</bean>
<bean id="desk" class="com.test.pojo.Desk">
<property name="id" value="1"></property>
<property name="price" value="12"></property>
</bean>