1.什么是Spring
spring是一个为简化企业开发而生的开源框架,我们使用Spring可以很简单、优雅地完成同样在EJB中要通过繁锁的配置和复杂的代码才能够实现的功能,不仅如此,Spring还是一个IOC(DI)和AOP容器。而且在IOC和AOP的基础上,Spring可以整合各种企业应用的开源框架和优秀的第三方类库。
2.Spring的IOC容器
2.1 IOC(Inversion of Control):控制反转
IOC也就是控制反转,他是Spring中的一种思想,通俗的来讲就是Spring技术将原本资源获取的方向进行了反转,由之前的组件主动的从容器中获取所需要的资源,变成了容器主动的将资源推送给需要的组件,这种行为也称为查找的被动形式。这样很大的提高了开发的效率,这就是Spring受欢迎的原因。
2.2 DI(Dependency Injection):依赖注入
依赖注入即组件以一些预先定义好的方式接受来自Spring容器的资源注入。DI其实就是IOC思想的一种具体实现,相对于IOC,DI的这种表述更为直接。
3.IOC容器在Spring中的实现
在Spring的IOC容器读取Bean的实例之前,Spring需要先将IOC容器本身实例化,Spring实例化IOC容器一般运用BeanFactory的子接口ApplicationContext。ApplicationContext所用到的主要实现类有ClassPathXmlApplicatinContext、FileSystemXmlApplicationContext、ConfigurableApplicationContext以及WebApplicationContext。
4.给bean的属性赋值
Spring首先调用ClassPathXmlApplicationContext实例化IOC容器,然后Sring IOC容器会读取bean的配置信息,拿到bean的配置信息之后在Spring容器中定义注册表,下一步Spring根据bean注册表实例化Bean对象,然后将bean的实例放到Spring容器中,供应用程序使用。
下面将介绍基于 XML 的配置文件来为bean赋值的几种方式:
4.1 依赖注入的方式为bean的属性赋值:(通过bean的set方法赋值)
首先编写我们的实体类:Person,在实体类中我们实现成员变量的getter、setter和tostring方法,然后写一个SayHello方法,输出一句话。
public class Person {
private String name;
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
public void SayHello(){
System.out.println("我的名字叫做"+name);
}
}
然后配置我们的xml文件,为bean赋值。
idea中创建spring的配置文件的步骤:File--New--XML ConfigurationFile--Spring Config。配置如下:
<?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.wei.springHelloword.bean.Person">
<property name="name" value="张三"></property>
</bean>
</beans>
最后我们编写测试类:Test
public class Test {
public static void main(String[] args) {
//1.创建spring的ioc对象
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获得Person对象 可以方法重载
Person person = ctx.getBean("person", Person.class);
//调用方法
person.SayHello();
}
}
结果:
一月 28, 2020 11:23:12 上午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@37f8bb67: startup date [Tue Jan 28 11:23:12 CST 2020]; root of context hierarchy
一月 28, 2020 11:23:12 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
我的名字叫做张三
Process finished with exit code 0
4.2 通过bean的构造器赋值
首先创建实体类Car,通过构造器赋值需要创建有参构造器和无参构造器,缺一不可。
public class Car {
private String brand;
private String crop;
private Double price;
public Car(){
}
public Car(String brand, String crop, Double price) {
this.brand = brand;
this.crop = crop;
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", crop='" + crop + '\'' +
", price=" + price +
'}';
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getCrop() {
return crop;
}
public void setCrop(String crop) {
this.crop = crop;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
}
编写xml文件为bean赋值
<?xml version="1.0" encoding="UTF-8"?>
<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" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!-- DI依赖注入的方式:构造器的方式-->
<!-- index:指定参数位置
type:指定参数类型
-->
<bean id="car1" class="com.wei.springDI.bean.Car">
<constructor-arg value="宝马" index="0"></constructor-arg>
<constructor-arg value="华晨"></constructor-arg>
<constructor-arg value="450000" type="java.lang.Double"></constructor-arg>
</bean>
</beans>
测试:
public class Test {
@Test
public void Testset(){
ClassPathXmlApplicationContext cxt =
new ClassPathXmlApplicationContext("application-di.xml");
Car car = cxt.getBean("car", Car.class);
System.out.println(car);
}
}
4.3 p命名空间来为bean赋值
为了简化XML文件的配置,越来越多的XML文件采用属性而非子元素配置信息。Spring从2.5版本开始引入了一个新的p命名空间,可以通过<bean>元素属性的方式配置Bean的属性。
首先需要引入p命名空间的依赖:xmlns:p="http://www.springframework.org/schema/p"
还是用Car的实体类。
xml配置文件为bean赋值:
<?xml version="1.0" encoding="UTF-8"?>
<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" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!--p命名空间,底层还是调用set方法 -->
<bean id="car3" class="com.wei.springDI.bean.Car"
p:brand="福特" p:crop="北京" p:price="300000" p:speed="260">
</bean>
</beans>
测试参考前面例子。
4.4 给bean赋值可以使用的值
4.4.1字面量:基本数据类型以及其封装类,String等类型都可以采用字面值注入的方式,
如果字面值中包含特殊字符,可以使用特定的语法<![CDATA[]]>把字面值包裹起来,编写简介。
xml:可以看到,如果出现特殊字符,可以使用转/义符代替特殊字符,但是代码不够简洁,使用特定语法就简洁很多。
<bean id="book" class="com.wei.springDI.bean.Book">
<property name="bookid" value="001"></property>
<!-- <property name="bookname" value="<<钢铁是怎样炼成的>>"></property>-->
<property name="bookname">
<value><![CDATA[钢铁是怎样炼成的]]></value>
</property>
</bean>
4.4.2 null值:如果不想给已有属性赋值可以使用<null/>标签为其赋
<bean id="null" class="com.wei.springDI.bean.Person">
<property name="id" value="103"></property>
<property name="name" value="菲菲"></property>
<property name="car"><null/></property>
</bean>
4.4.3 给bean的级联属性赋值:调用其他bean的属性可以使用其id.属性来设置级联属性
<!--引用其他的bean ref -->
<bean id="person" class="com.wei.springDI.bean.Person">
<property name="id" value="101"></property>
<property name="name" value="张三"></property>
<property name="car" ref="car1"></property>
<!-- 给级联属性赋值 -->
<property name="car.speed" value="250"></property>
</bean>
4.4.4 引用外部已声明的bean:调用ref,填写外部以及声明好的bean的id即可使用其属性
<!--引用其他的bean ref -->
<bean id="person" class="com.wei.springDI.bean.Person">
<property name="id" value="101"></property>
<property name="name" value="张三"></property>
<property name="car" ref="car1"></property>
</bean>
4.4.5 内部bean:当bean实例仅仅给一个特定的属性使用时,可以将其声明为内部bean。内部bean声明直接包含在<property>或<constructor-arg>元素里,不需要设置任何id或name属性内部bean不能使用在任何其他地方。
<!-- 内部bean -->
<bean id="person1" class="com.wei.springDI.bean.Person">
<property name="id" value="102"></property>
<property name="name" value="大力"></property>
<property name="car">
<!-- 内部bean只能在内部使用 -->
<bean class="com.wei.springDI.bean.Car">
<property name="brand" value="保时捷"></property>
<property name="crop" value="..."></property>
<property name="price" value="2000000"></property>
<property name="speed" value="500"></property>
</bean>
</property>
</bean>
4.5 集合属性
在Spring中可以通过一组内置的XML标签来配置集合属性,例如:<list>,<set>或<map>。
4.5.1 List
实体类:
public class PersonList {
private String name;
private List<Car> cars;
@Override
public String toString() {
return "PersonList{" +
"name='" + name + '\'' +
", cars=" + cars +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Car> getCars() {
return cars;
}
public void setCars(List<Car> cars) {
this.cars = cars;
}
}
xml:可以引用已创建的bean为list集合
<!-- List集合 -->
<bean id="personList" class="com.wei.springDI.bean.PersonList">
<property name="name" value="wei"></property>
<property name="cars">
<list>
<ref bean="car1"></ref>
<ref bean="car2"></ref>
<ref bean="car3"></ref>
</list>
</property>
</bean>
4.5.2 Map:<map>标签里可以使用多个<entry>作为子标签。每个条目包含一个键和一个值。
<!-- Map集合 -->
<bean id="personMap" class="com.wei.springDI.bean.PersonMap">
<property name="name" value="jerry"></property>
<property name="cars">
<map>
<entry key="AA" value-ref="car2"></entry>
<entry key="BB" value-ref="car3"></entry>
<entry key="CC" value-ref="car1"></entry>
</map>
</property>
</bean>
4.5.3 集合类型的bean:区别于内部bean,我们可以将集合bean的配置拿到外面,供其他bean引用。其他bean只需要利用ref:+集合bean的id即可引用集合bean内的数据。
<!--集合bean-->
<util:list id="listBean">
<ref bean="car"></ref>
<ref bean="car1"></ref>
<ref bean="car3"></ref>
</util:list>
引用集合bean
<!-- List集合 -->
<bean id="personList" class="com.wei.springDI.bean.PersonList">
<property name="name" value="wei"></property>
<property name="cars" ref="listBean">
<list>
</list>
</property>
</bean>
4.6 FactoryBean(工厂bean)
Spring中有两种类型的bean,一种是普通bean,另一种是工厂bean,即FactoryBean。工厂bean跟普通bean不同,其返回的对象不是指定类的一个实例,其返回的是该工厂bean的getObject方法所返回的对象。
要想使用FactoryBean,必须实FactoryBean接口,并且实现他的三个未实现的方法。
public class CarFactoryBean implements FactoryBean<Car> {
//工厂bean具体创建的bean对象是由getObject方法来返回的
@Override
public Car getObject() throws Exception {
return new Car("五菱宏光","中国",200);
}
//返回具体的bean对象的类型
@Override
public Class<?> getObjectType() {
return Car.class;
}
//bean可以是单例的 也可以是原型的(非单例)
@Override
public boolean isSingleton() {
return true;
}
}
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">
<!-- 通过FactoryBean 来配置bean
FactoryBean具体返回的对象是由getObject方法来决定的
-->
<bean id="car" class="com.wei.factorybean.bean.CarFactoryBean"></bean>
</beans>
测试:
public class test {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-factorybean.xml");
Car car = ctx.getBean("car", Car.class);
System.out.println(car);
}
}