欢迎访问:我的个人网站
Spring框架提供了非常多的模块,如果使用基本的Spring功能,需只需要引入其核心的几个包即可,前四个正是Spring位于核心容器内的几个模块。后两个与日志相关。
- spring-beans
- spring-core
- spring-context
- spring-expression
- commons-logging
- log4j
1.IOC
IOC可以接管对象的实例化工作,不用自己去创建,只需进行相关的配置即可完成,IOC实际上是通过读取我们配置的xml文件,使用dom4j进行解析,获取我们所需要实例化的类所在的包,以及实例化该类时所需要提供的id。然后通过反射加载这个被接管的类,后续我们可以获取,一个简单案例演示一个类被接管并获取到的过程:
(1)新建工程,导包
(2)新建一个对象Person,后续让Spring接管这个类的实例化工作:
public class Person {
private String name;
private Integer age;
//省略get/set
}
(3)新建Spring配置文件并注入Person,配置文件中的头可以从下载Spring时附带的文件夹schema中寻找。如果使用了IDEA,新建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="person" class="com.bestbigkk.domain.Person">
</bean>
</beans>
(4)通过Spring获得一个Person对象:
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
Person person = (Person) context.getBean("person");
System.out.println(person);
}
}
2.bean 实例化三种方式
(1)配置文件,指定一个bean注入, 这种方式使用无参数构造方法进行构建, 如果此时没有默认无参数构造方法,会报错no default construct found…
<bean id="person" class="com.bestbigkk.domain.Person">
(2)使用静态工厂,创建静态方法返回类对象。需要在配置bean的时候,为其指定一个beanFactory工厂,并指定这个工厂里面哪个静态方法是用于获取bean的实例的,后续再获取这个bean实例时候,相当于直接使用了:工厂类名.获取实例静态方法名 的形式获取bean的一个实例:
public class Person {
private String name;
private Integer age;
//...
}
public class PersonFactory {
public static Person getBean(){
System.out.println("静态工厂获取实例");
return new Person();
}
}
配置这个bean,之后就可以获取其实例:
<bean id="person" class="com.bestbigkk.domain.PersonFactory" factory-method="getBean"></bean>
(3)使用实例工厂,通过一个工厂的实例对象来获取bean的对象。需要如下流程:
创建一个bean的实例化工厂:
public class PersonFactory {
public Person getBean(){
System.out.println("实例工厂获取实例");
return new Person();
}
}
配置beanFactory实例化工厂:
<bean id="personFactory" class="com.bestbigkk.domain.beanFactory"> </bean>
配置person,指定实例化它的工厂以及实例化方法:
<bean id="person" factory-bean="personFactory" factory-method="getBean"> </bean>
3.bean标签常用含义:
- id: 指定这个bean在注入的时的名字,后续我们通过工厂getBean(name)获取某个对象的时候,提供其注入时候的名字即可。不能包含特别符号。
- class: 被注入bean的全路径。
- name: 与id类似,但是id中不能包含特殊符号,这里可以。name实际上是遗留的,还是使用id属性即可。
- scope: 指定被注入bean的作用范围,存在以下几个选项:
- singleton:默认值 ,单例的,这个对象只会创建一次,可以连续获取两个对象比较其内存地址。
- prototype:多例的,每次创建都是一个新的对象。
- request:WEB项目中,Spring创建一个Bean对象,将其存在于request对象中。
- response:WEB项目中,Spring创建一个Bean对象,将其存在于response对象中。
- session:WEB项目中,Spring创建一个Bean对象,将其存在于Session对象中。
- globalSerssion:WEB项目中,应用在prolet环境中,如果没有prolet环境,那么和Session一样,放在Session域里面。
4.bean标签的属性注入:
在实例化一个对象的时候,可以选择为这个对象设置一些值, 在Java中可以选择使用以下常规的方式进行注入:
在Spring中仅仅支持set方法注入(使用较多) 以及构造方法注入,示例:
创建一个Bean:
public class Person {
private String name;
private Integer age;
public Person(){
}
public Person(String name, Integer age){
this.age = age;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
使用有参构造注入:
需要在配置bean的时候,指定要注入的属性以及值, 指定的参数个数必须有构造函数可以匹配上,否则无法实例化。在正确配置之后,实例化这个bean的时候就会使用指定的构造方法初始化并赋值::
<bean id="person" class="com.bestbigkk.domain.Person" scope="prototype">
<constructor-arg name="age" value="21"> </constructor-arg>
<constructor-arg name="name" value="KK"> </constructor-arg>
</bean>
获取实例:
Person person1 = (Person) context.getBean("person");
System.out.println(person1.toString());
//结果:
Person{name='KK', age=21}
使用set方法注入属性:
实例化一个bean的时候,使用set方法进行设置:需要在配置bean之后,使用property标签指定设置的属性名以及属性值即可完成注入,需要注入的属性必须为其提供set方法。对于简单属性类型可以使用下面的方式直接注入:
<bean id="person" class="com.bestbigkk.domain.Person" scope="prototype">
<property name="name" value="KK"> </property>
</bean>
在某些情况下,一个对象里面会包含另外一个对象,比如在Web开发中,Service层需要使用使用Dao层中的对象来完成数据库的持久化操作,此时可以考虑将Dao层中的对象直接注入到Service中的对象,不再使用new的方式进行, 针对这一情况也可以使用set方法进行注入:
使用一个简单的例子来表示这种注入方式:一个Person类表示一个学生,其中包含了一个表示成绩的对象Score,由于Person引入了Score对象,可以使用set形式进行注入
(1)创建Score:
public class Score {
private Integer math;
private Integer chinese;
}
(2)创建Person:
public class Person {
private String name;
private Integer age;
private Score score;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
public Score getScore() { return score; }
public void setScore(Score score) { this.score = score; }
}
(3)配置Score:
<bean id="score" class="com.bestbigkk.domain.Score"> </bean>
(4)配置Person, 并注入Score对象,使用ref属性指定引用哪个bean的id作为对象注入。本例子中注入Score对象,且配置的Score类id为score:
<bean id="person" class="com.bestbigkk.domain.Person">
<property name="score" ref="score">
</bean>
P命名空间注入
(1)需要修改.xml文件的文件头:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
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">
新增:
xmlns:p="http://www.springframework.org/schema/p"
(2)在配置的bean里面配置属性,此时p将作为一个属性存在,使用[p:属性名]的形式为指定的属性设置值:
<bean id="person" class="com.bestbigkk.domain.Person" p:name="KK" p:age="21"></bean>
注入复杂数据类型
Spring允许向一个对象里面注入复杂的数据类型,比如数组,List,Map, Properties数据:
//节约篇幅,省略了getXXX()/setXXX()方法,如果运行中无setXXX()方法会报错。
public class Person {
private String[] hobby;
private List<Integer> score;
private Map<Integer, String> map;
private Properties properties;
}
为这个bean注入属性:
<bean id="person" class="com.bestbigkk.domain.Person" scope="prototype">
<!--注入数组, List类型的数据-->
<property name="hobby">
<list>
<value>音乐</value>
<value>旅行</value>
</list>
</property>
<property name="score">
<list>
<value>100</value>
<value>200</value>
</list>
</property>
<!--注入map类型的数据-->
<property name="map">
<map>
<entry key="1" value="A"> </entry>
<entry key="2" value="B"> </entry>
<entry key="3" value="C"> </entry>
<entry key="4" value="D"> </entry>
<entry key="5" value="E"> </entry>
</map>
</property>
<!--注入Properties类型数据-->
<property name="properties">
<props>
<prop key="userName">KK</prop>
<prop key="userPwd">123</prop>
</props>
</property>
</bean>
5.使用注解进行Bean的管理
5.1注解
注解是一种存在于代码里面的特殊标记,使用不同的注解可以完成它所约定的功能。注解可以使用在类上面,属性上面,方法上面。
Spring里面使用注解的话,除了使用一些核心包之外,还需要使用spring-aop包,关于注解的一些操作被包含在这个包里面。
在使用注解进行开发的时候,在.xml配置文件中,约束也需要进行适当得人更新,需要进行调整(引入了spring-context.xsd)。需要在文件中开启注解扫描。然后就可以在代码使用注解。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="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">
<!--开启注解方式1,扫描类,方法,属性-->
<context:component-scan base-package="com.bestbigkk.domain"></context:component-scan>
<!--开启注解方式2,仅仅扫描属性上面的注解-->
<context:annotation-config></context-annotation-config>
</beans>
开启注解指的是Spring将通过配置的包进行注解的扫描,进而按照1注解实现不同功能,base-package指定了要扫描的范围:
- 可以为多个包, 使用逗号分隔:base-package=“com.bestbigkk.domain, com.bestbigkk.service”
- 会扫描指定包下的所有嵌套包,base-package=“com”, 则扫描com下的所有类以及子包中的类。
5.2使用注解创建对象
在目标类对象上面使用 @Component 即可:
@Component
public Class Person{
//...
}
等价于:
<bean id="person" class="com.bestbigkk.domain.Person"></bean>
@Component 注解允许设置一个属性value,作为实例化id的值,如果未设置(如上),则id值默认为当前类的全小写名称,也就是:person。当然也可以自己设置,后续获取实例的时候需要使用该值:
@Component(value="PERSON")
public class Person{
//...
}
classPathXmlApplicationApplication.getBean("PERSON");
创建对象有4个注解,除了 @Component 之外,还衍生出来三个另外的注解,他们的功能来讲都是一致的,但是为了更方便开发过程中区分层与层之间的关系。使得其用途更加清晰。
- @Controller: 控制层
- @Service: 服务层
- **@Repository:**持久层
在创建对象的时候,如要指定这个对象的作用域,可以使用**@Scope**注解进行标注,这个注解默认值也是singleton,如果要改变的话,只需要为其属性value赋值即可:
@Controller(value="Person")
@Scope(value="prototype")
public class Person(){
//...
}
5.3使用注解注入属性
使用注解方式注入属性的时候,不需要为属性设置对用的set方法,注入属性使用**@Autowired** 进行设置,当对一个属性添加了**@Autowired** 注解的时候,Spring会检查这个属性所属的类,并再工程中进行扫描以查询这个类, 最后注入。针对这个示例,Spring会去寻找一个名为Score的类,而不是通过Score类上的**@Component** 注解的值确定的。
//被注入类
@Component
@Scope(value = "prototype")
public class Score {
public Integer math = 1;
public Integer chinese = 2;
}
//注入类
@Component
@Scope(value = "prototype")
public class Student {
private String name;
private Integer age;
@Autowired
private Score score;
}
除了使用**@Autowire** 注解之外,属性的注入还可以使用**@Resource** 进行处理, @Autowire 是自动寻找被加载的类进而注入,而**@Resource** 注解则是确定要为其制定一个属性name 来确认注入哪个类,name的值需要与被注入对象的 @Component(value) 注解值一致。
根据上面所述,可以将注解+配置文件的混合使用,在.xml文件里面配置bean,然后用**@Resource(name=“Bean的ID值”)** 注入对象。
@Component
@Scope(value = "prototype")
public class Student {
private String name;
private Integer age;
@Resource(name="score")
private Score score;
}
6.IOC 与 DI的区别
IOC : 控制翻转,通过对bean进行配置,让Spring接管对Bena的实例化工作。
DI : 依赖注入,指的是在创建对象的时候,可以为这个对象的2属性注入值。
DI 需要依赖于IOC进行,因为IOC进行对象的实例化工作,如果没有进行实例化,那么就谈不上为这个对象的属性设置值。
7Spring整合Web项目原理
在以上的所有示例中,从Spring获取我们配置好的对象都是通过ClassPathXmlApplicationContext类进行的,这样虽然可以使用,但是在真正的WEB开发中,如果使用了上面的这种方法,那么所有请求来到一个Service时候,都要建立一个ClassPathXmlApplicationContext对象进行操作,这样的话对资源使用使很不友好的。Spring针对这个问题做了以下的处理流程: 在服务器启动的时候,也就是ServletContext初始化的时候,通过监听器直到何时初始化完毕,然后建立这个对象加载Spring的配置文件,并将这个对象加入到ServletContext域里面去。以完成进行初始化工作。后续在获取对象的时候,首先到ServletContext获取ClassPathXmlApplicationContext对象,然后得到对象。