Spring学习总结(一)

Spring框架框架的核心功能有两个:

  1. Spring容器作为超级大工厂,负责创建、管理所有的java对象,这些java对象被称作Bean。
  2. Spring容器管理容器中Bean之间的依赖关系,Spring使用一种被称作“依赖注入”的方式来管理Bean之间的依赖关系。

1 IOC和DI

    IOC(Inversion of Control):其思想是反转资源获取的方向。传统的资源查找方式要求组件向容器发起请求查找资源,作为回应,容器实时的返回资源。而应用了IOC之后,则是容器主动的将资源推送给它所管理的组件,组件要做的则是选择一种合适的方式来接受资源。这种行为也成为被查找的被动形式。

    DI(Depedency Injection):IOC的另一种表达方式,即组件以一些预先定义好的方式(例如:setter方法)接受来自容器的资源注入。相对于IOC而言,这种表述更直接。

2 IOC的发展历程

             举一个例子,需求是需要生成一个HTML和PDF的不同类型的报表。以前我们一般会这样做,如UML类图1所示:


图1

   service层依赖ReportGenrator接口,pdf和html的Generator去实现ReportGenrator接口,然后ReportService去关联PdfReportGenerator类和HtmlReportGenerator类。这样子Service层与其报表生成的两个类的耦合度就非常高。发展到后来开发者们开始利用工厂设计模式,service层不再去和PdfReportService和HtmlReportGenerator类去关联,而是去关联ReportGeneratorFactory工厂,由工厂去生产这两个类。当service层需要时向工厂提出需求,有工厂负责生产。如图2所示:


图2

   发展到今天,Spring采用了IOC即反转控制。此时service层不再需求去主动请求PdfReportGenerator和HtmlReportGenerator的资源,而是有容器Container主动去注入资源,也就是service层被动接受来自Container的资源。service层和PdfReportGenerator、HtmlReportGenerator类无耦合,整个设计的耦合度大大降低。如图3所示:

 

图3 

3 在Spring的IOC容器中配置bean

   这里以HelloWorld为例,首先给出所有代码,然后再去做一个小结。

<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">package com.alibaba.beans;

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

public class Main
{
	public static void main(String[] args)
	{
		//创建spring的IOC容器对象
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		//从IOC容器中获取bean实例
		HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");

		helloWorld.hello();
	}
}</span></span></span>

    Bean代码:

<span style="font-size:18px;"><span style="font-size:18px;">package com.alibaba.beans;

public class HelloWorld
{
	private String name;

	public void setName(String name)
	{
		System.out.println("setName: " + name);
		this.name = name;
	}
	
	public void hello()
	{
		System.out.println("hello:" + name);
	}
	
	public HelloWorld()
	{
		System.out.println("HelloWorld's constructor ...");
	}
}
</span></span>

    applicationContext.xml代码:

<span style="font-size:18px;"><span style="font-size:18px;"><?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 -->
	<bean id="helloWorld" class="com.alibaba.beans.HelloWorld">
	    <property name="name" value="Spring"></property>
	</bean>
</beans>
</span></span>

   id作为Bean的名称,在IOC容器中必须是唯一的。若id没有指定,则Spring会将类的全限定名作为bean的名字。这里的class即就是bean的全类名,spring会通过反射在IOC容器中创建Bean,所以要求Bean中必须有无参数的构造器。在Main类中的ApplicationContext就是IOC容器,SpringIOC容器读取Bean配置创建Bean实例之前,必须对它进行实例化才可以从IOC容器中获取bean实例。

4 Spring容器

   Spring提供了两种类型的IOC容器实现:

  • BeanFactory:IOC容器的基本实现。
  • ApplicationContext:提供了更多的高级特性,是BeanFactory的子接口,它增强了BeanFactory的功能。

   大部分时候,都不会使用BeanFactory实例作为Spring容器,而是使用ApplicationContext实例作为容器。ApplicationContext的主要实现类有两个:

  1. ClassPathXmlApplicationContex:从类路径下加载配置文件。
  2. FileSystemXmlApplicationContext:从文件系统中加载配置文件。

    ConfigurableApplicationContext扩展于ApplicationContext,新增加两个主要方法:refresh()close(),让ApplicationContext具有启动、刷新和关闭上下文的能力。ApplicationContext在初始化上下文时就实例化所有单例的Bean。接下来列出其类的关系图及UML类图,分别如图4、图5所示。

                     

                                     

图4


           

图5

5 依赖注入的方式

   Spring支持的依赖注入主要有两种:属性注入(摄值注入)和构造器注入。属性注入即通过setter方法注入Bean的属性值或依赖的对象。属性注入使用<property>元素,使用name属性指定Bean的属性名称,value属性或<value>子节点指定属性值。属性注入是实际应用中最常用的注入方式。

6 引用其他Bean

   在这里我们添加一个Car类和Person类,让Person类去引用Car类。附上Car和Person类的代码

package com.alibaba.beans;

public class Person
{
	private String name;
	private int age;
	private Car car;

	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;
	}

	public Car getCar()
	{
		return car;
	}

	public void setCar(Car car)
	{
		this.car = car;
	}

	@Override
	public String toString()
	{
		return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
	}

	
}

package com.alibaba.beans;

public class Car
{
	private String company;
	private String brand;

	private int maxSpeed;
	private float price;

	public Car(String company, String brand, float price)
	{
		super();
		this.company = company;
		this.brand = brand;
		this.price = price;
	}

	public Car(String company, String brand, int maxSpeed)
	{
		super();
		this.company = company;
		this.brand = brand;
		this.maxSpeed = maxSpeed;
	}

	public Car(String company, String brand, int maxSpeed, float price)
	{
		super();
		this.company = company;
		this.brand = brand;
		this.maxSpeed = maxSpeed;
		this.price = price;
	}

	@Override
	public String toString()
	{
		return "Car [company=" + company + ", brand=" + brand + ", maxSpeed=" + maxSpeed + ", price=" + price + "]";
	}
	public Car()
	{
		
	}
}

   这样当Person类去引用Car类时,我们的容器里面也得进行配置。applicationContext里面的代码重新更新如下:

<?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 -->
	<bean id="helloWorld" class="com.alibaba.beans.HelloWorld">
		<property name="name" value="Spring"></property>
	</bean>

	<bean id="car" class="com.alibaba.beans.Car">
		<constructor-arg value="bmw" type="java.lang.String"></constructor-arg>
		<constructor-arg type="java.lang.String">
			<value><![CDATA[<shanghai>]]></value>
		</constructor-arg>
		<constructor-arg type="int">
			<value>250</value>
		</constructor-arg>
	</bean>

	<bean id="person" class="com.alibaba.beans.Person">
		<property name="name" value="Tom"></property>
		<property name="age" value="24"></property>
		<property name="car" ref="car"></property>
	</bean>
</beans>

   这里我们要实现Person去访问Car,也就是实现Bean之间的互访,就必须在Bean配置文件中指定对Bean的引用。在Bean的配置文件中可以通过<ref>元素或者ref属性为Bean的属性或者构造器参数指定对Bean的引用。看到上面我们进行了赋值都是单个属性,其实spring里面支持级联属性,这里需要注意的是在Spring里面需要先初始化后才可以为级联属性赋值,否则会有异常,和Struts2不同。

7 集合属性

   为了方便,我们重新建一个包以便我们对集合属性进行学习,这里重新建一个包,其包括了Person类和Main类(以便进行集合属性学习),Person里面的car属性变成了集合,即一个人可以有多辆汽车了,对于Person类和容器中的代码得稍作修改了。现在给出这个包下,Person类和Main类(这个类里面只会去获取Person类的实例)。

package com.alibaba.beans.collections;

import java.util.List;

import com.alibaba.beans.Car;

public class Person
{
	private String name;
	private int age;
	private List<Car> cars;

	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;
	}

	public List<Car> getCars()
	{
		return cars;
	}

	public void setCars(List<Car> cars)
	{
		this.cars = cars;
	}

	@Override
	public String toString()
	{
		return "Person [name=" + name + ", age=" + age + ", cars=" + cars + "]";
	}

	
}

   这个包下的Main类(再次说一遍这个项目里面现在有两个Main类了,运行时只需要点击这个Main类让其运行,我们的目的只是通过这个例子去熟悉集合属性)。

package com.alibaba.beans.collections;

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

public class Main
{
	public static void main(String[] args)
	{
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		Person p = (Person) ctx.getBean("person1");
		
		System.out.println(p);
	}
}

   此时IOC容器里面的配置稍作修改,主要还是为了学习集合属性。

<?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 -->
	<bean id="helloWorld" class="com.alibaba.beans.HelloWorld">
		<property name="name" value="Spring"></property>
	</bean>

	<bean id="car" class="com.alibaba.beans.Car">
		<constructor-arg value="bmw" type="java.lang.String"></constructor-arg>
		<constructor-arg type="java.lang.String">
			<value><![CDATA[<shanghai>]]></value>
		</constructor-arg>
		<constructor-arg type="int">
			<value>250</value>
		</constructor-arg>
	</bean>

	<bean id="car1" class="com.alibaba.beans.Car">
		<constructor-arg value="audi" type="java.lang.String"></constructor-arg>
		<constructor-arg type="java.lang.String">
			<value><![CDATA[<guangzhou>]]></value>
		</constructor-arg>
		<constructor-arg type="int">
			<value>260</value>
		</constructor-arg>
	</bean>

	<bean id="person1" class="com.alibaba.beans.collections.Person">
		<property name="name" value="Tom"></property>
		<property name="age" value="24"></property>
		<property name="cars">
			<list>
				<ref bean="car" />
				<ref bean="car1" />
			</list>
		</property>
	</bean>
</beans>

   这里做一个小结:Spring可以通过一组内置的xml标签(例如:<list>, <set> <map>)来配置集合属性配置java.util.List类型的属性,需要指定<list> 标签,在标签里包含一些元素.这些标签可以通过<value>指定简单的常量值,通过<ref>指定对其他Bean的引用.通过<bean>指定内置Bean定义.通过<null/>指定空元素.甚至可以内嵌其他集合数组的定义和List一样,都使用<list>;配置java.util.Set需要使用<set>标签,定义元素的方法与List样。接下来看看Map集合属性的应用。同样为了去学习Map集合属性,需要再次新建一个NewPerson类,然后再applicationContext里面进行更改,最后再第二个新建的Main类中去获取实例进行测试。现在给出代码。

package com.alibaba.beans.collections;

import java.util.Map;

import com.alibaba.beans.Car;

public class NewPerson
{
	private String name;
	private int age;
	private Map<String, Car> cars;

	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;
	}

	public Map<String, Car> getCars()
	{
		return cars;
	}

	public void setCars(Map<String, Car> cars)
	{
		this.cars = cars;
	}

	@Override
	public String toString()
	{
		return "NewPerson [name=" + name + ", age=" + age + ", cars=" + cars + "]";
	}

}

<?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 -->
	<bean id="helloWorld" class="com.alibaba.beans.HelloWorld">
		<property name="name" value="Spring"></property>
	</bean>

	<bean id="car" class="com.alibaba.beans.Car">
		<constructor-arg value="bmw" type="java.lang.String"></constructor-arg>
		<constructor-arg type="java.lang.String">
			<value><![CDATA[<shanghai>]]></value>
		</constructor-arg>
		<constructor-arg type="int">
			<value>250</value>
		</constructor-arg>
	</bean>

	<bean id="car1" class="com.alibaba.beans.Car">
		<constructor-arg value="audi" type="java.lang.String"></constructor-arg>
		<constructor-arg type="java.lang.String">
			<value><![CDATA[<guangzhou>]]></value>
		</constructor-arg>
		<constructor-arg type="int">
			<value>260</value>
		</constructor-arg>
	</bean>

	<bean id="person1" class="com.alibaba.beans.collections.Person">
		<property name="name" value="Tom"></property>
		<property name="age" value="24"></property>
		<property name="cars">
			<list>
				<ref bean="car" />
				<ref bean="car1" />
			</list>
		</property>
	</bean>

	<span style="color:#FF0000;"><!-- 配置Map属性 --></span>
	<bean id="newPerson" class="com.alibaba.beans.collections.NewPerson">
		<property name="name" value="micel"></property>
		<property name="age" value="25"></property>
		<property name="cars">
			<map>
				<entry key="AA" value-ref="car"></entry>
				<entry key="BB" value-ref="car1"></entry>
			</map>
		</property>
	</bean>
</beans>
package com.alibaba.beans.collections;

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

public class Main
{
	public static void main(String[] args)
	{
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		Person p = (Person) ctx.getBean("person1");
		
		System.out.println(p);
		System.out.println("---------------------我是分割线-------------------------");
		
		NewPerson np = (NewPerson) ctx.getBean("newPerson");
		System.out.println(np);
	}
}

   在此对Map集合属性进行一个小结:(1)Java.util.Map通过<map>标签定义,<map>标签里可以使用多个<entry>作为子标签.每个条目包含一个键和一个值;(2)可以将Map的键和值作为<entry>的属性定义:简单常量使用keyvalue来定义;Bean引用通过key-refvalue-ref属性定义;

8 使用p命名空间

   为了简化XML文件的配置,越来越多的XML文件采用属性而非子元素配置信息。Spring2.5版本开始引入了一个新的p命名空间,可以通过<bean>元素属性的方式配置Bean的属性使用p命名空间后,基于XML的配置方式将进一步简化。下面在容器中新建一个person2的bean,然后使用p命名空间去定义,最后去第二次定义的Main里面获取实例进行测试。下面给出代码。


<?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:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	<!-- 配置bean -->
	<bean id="helloWorld" class="com.alibaba.beans.HelloWorld">
		<property name="name" value="Spring"></property>
	</bean>

	<bean id="car" class="com.alibaba.beans.Car">
		<constructor-arg value="bmw" type="java.lang.String"></constructor-arg>
		<constructor-arg type="java.lang.String">
			<value><![CDATA[<shanghai>]]></value>
		</constructor-arg>
		<constructor-arg type="int">
			<value>250</value>
		</constructor-arg>
	</bean>

	<bean id="car1" class="com.alibaba.beans.Car">
		<constructor-arg value="audi" type="java.lang.String"></constructor-arg>
		<constructor-arg type="java.lang.String">
			<value><![CDATA[<guangzhou>]]></value>
		</constructor-arg>
		<constructor-arg type="int">
			<value>260</value>
		</constructor-arg>
	</bean>

	<bean id="person1" class="com.alibaba.beans.collections.Person">
		<property name="name" value="Tom"></property>
		<property name="age" value="24"></property>
		<property name="cars">
			<list>
				<ref bean="car" />
				<ref bean="car1" />
			</list>
		</property>
	</bean>

	<!-- 配置Map属性 -->
	<bean id="newPerson" class="com.alibaba.beans.collections.NewPerson">
		<property name="name" value="micel"></property>
		<property name="age" value="25"></property>
		<property name="cars">
			<map>
				<entry key="AA" value-ref="car"></entry>
				<entry key="BB" value-ref="car1"></entry>
			</map>
		</property>
	</bean>

      <span style="color:#FF0000;"><!-- 通过p命名空间为bean的属性赋值,需要先导入p命名空间,相对于传统的配置方式比较简洁 --></span>
	<bean id="person2" class="com.alibaba.beans.collections.Person" p:name="Jackon"
	p:age="30">
	</bean>
</beans>

   由于博客篇幅太长了,接下来的内容会在《Spring学习总结一(续1)》里面,可以参看本人有关Spring的博客分类。本篇博客参照了尚硅谷的佟刚视频和李刚的JavaEE轻量级开发一书,所有的代码将在总结一完结时给出下载地址。




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值