Spring快速入门

引言

最近几天一直在忙着学习数据结构和算法,关于JavaEE的框架也有一阵子没更新了。那么今天就来聊一聊Spring框架吧,针对该框架写一篇快速入门的文章。

Spring简介

Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。

  • 目的:解决企业应用开发的复杂性
  • 功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
  • 范围:任何Java应用

Spring是一个轻量级控制反转(IOC)和面向切面(AOP)的容器框架。

配置Bean

首先来说一说在Spring框架中如何去配置Bean。
通过一个简单案例感受一下:
首先得导入Spring框架的jar包,然后创建一个类:

package com.itcast.spring.bean;

public class HelloWorld {

	private String name;

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

	public String getName() {
		return name;
	}

	public void hello() {
		System.out.println("hello:" + name);
	}
}

在传统的写法中,我们要想调用HelloWorld类的hello()方法,我们需要手动创建HelloWorld的实例,然后调用setName()方法给name赋值,接着调用hello()方法。但是有了Spring框架之后,对于对象的创建和属性的赋值都不需要我们操心,框架能够帮助我们完成。所以接下来创建Spring框架的配置文件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="helloWorld" class="com.itcast.spring.bean.HelloWorld">
		<property name="name" value="Spring"></property>
	</bean>
	
</beans>

对于这段简单的配置,可以解释一下。bean是beans下的一个子节点,配置的是一个bean类的信息,然后是bean节点下的属性:

  • id:标识容器中的bean,id是唯一的
  • class:bean的全类名,因为框架是通过反射的方式在IOC容器中创建bean的实例,所以你需要提供类的全路径,这在很多框架中都能得到体现

然后是property,该节点配置的是bean类中的属性信息,name即为属性名,但是需要注意的是,这个name值是根据setXXX()方法进行匹配的,如果没有setXXX()方法或者setXXX()方法和类中的属性名不一致,将会导致异常产生。而value就是属性的值。
配置好后,我们编写测试代码:

public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");
		helloWorld.hello();
}

首先通过ClassPathXmlApplicationContext去构造ApplicationContext 对象,传入配置文件名,接着通过getBean()方法得到HelloWorld实例,传入的是在配置文件中bean的id属性值。
运行结果:

hello:Spring

需要注意的是,在bean类中你必须提供一个无参的构造方法,因为反射的实现需要无参构造。
到这里,一个入门的Spring案例就完成了。

Spring容器

接下来,我们细细地研究一下。
在SpringIOC容器读取bean配置创建bean实例之前,必须对它进行实例化,只有在容器实例化后,才可以从IOC容器中获取bean实例并使用。
在Spring中提供了两种类型的IOC容器实现:

  1. BeanFactory:IOC容器的基本实现
    BeanFactory是Spring框架的基础设施,面向Spring本身
  2. ApplicationContext:提供了更多的高级特性,是BeanFactory的子接口
    ApplicationContext面向使用Spring框架的开发者,几乎所有的应用场合都直接使用ApplicationContext而非底层的BeanFactory

但无论使用何种方式,配置文件的写法都是一样的。
ApplicationContext是BeanFactory的子接口,它有两个实现类:

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

所以获得ApplicationContext的实例可以有两种方式,刚才的案例中使用的就是第一种方式。

获得了Spring容器后,我们是如何去获得bean实例的呢?
通过getBean()方法:
在这里插入图片描述
可以看到,ApplicationContext提供了多个getBean()方法的重载,所以对于bean实例的获取,除了通过id属性值获取以外,还可以通过bean的类型获取:

public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		HelloWorld helloWorld = ctx.getBean(HelloWorld.class);
		helloWorld.hello();
}

这样也能获取到bean的实例,而且有一个好处就是不用强制类型转换了。

属性值的注入

在Spring框架中,有两种方式可以对bean类的属性进行赋值:

  1. 属性注入
    属性注入在开始的案例中已经使用到了,就是通过bean节点下的property节点进行注入,它通过setXXX()方法注入属性值,属性注入是实例应用开发中最常用的注入方式
  2. 构造方法注入
    构造方法注入顾名思义就是通过构造方法注入属性值,它通过bean节点下的constructor-arg节点进行注入

对于构造方法注入属性值,有必要单独提取出来讲解一下,我们来看一个案例。
创建一个bean类:

package com.itcast.spring.bean;

public class Car {

	private String brand;
	private String corp;
	private double price;
	private int maxSpeed;
	
	public Car(String brand, String corp, double price) {
		super();
		this.brand = brand;
		this.corp = corp;
		this.price = price;
	}

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

然后配置一下:

<?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="car" class="com.itcast.spring.bean.Car">
		<constructor-arg value="Audi"></constructor-arg>
		<constructor-arg value="ShangHai"></constructor-arg>
		<constructor-arg value="250000"></constructor-arg>
	</bean>
</beans>

接下来编写测试代码:

public static void main(String[] args) {
	ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
	Car car = (Car) ctx.getBean("car");
	System.out.println(car);
}

运行结果:

Car [brand=Audi, corp=ShangHai, price=250000.0, maxSpeed=0]

因为是通过构造方法注入属性值,所以可以不需要setXXX()方法,从配置中可以知道,属性值是通过配置的顺序进行注入的,那么接下来我们修改一下Car类:

package com.itcast.spring.bean;

public class Car {

	private String brand;
	private String corp;
	private double price;
	private int maxSpeed;

	public Car(String brand, String corp, double price) {
		super();
		this.brand = brand;
		this.corp = corp;
		this.price = price;
	}

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

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

我们在Car类中新增了一个构造方法,然后我们重新配置一下bean:

<?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="car2" class="com.itcast.spring.bean.Car">
		<constructor-arg value="BMW"></constructor-arg>
		<constructor-arg value="BeiJing"></constructor-arg>
		<constructor-arg value="240"></constructor-arg>
	</bean>
</beans>

我们想通过这三个属性值来得到一个Car的实例,接下来编写测试代码:

public static void main(String[] args) {
	ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
	Car car = (Car) ctx.getBean("car2");
	System.out.println(car);
}

运行结果:

Car [brand=BMW, corp=BeiJing, price=240.0, maxSpeed=0]

问题就出现了,我明明是想通过第二个构造方法构造对象,传入的240是maxSpeed的值,但它仍然使用了第一个构造方法,所以仅仅靠参数顺序来注入是不合理的。
不过不用担心,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="car2" class="com.itcast.spring.bean.Car">
		<constructor-arg value="BMW" type="java.lang.String"></constructor-arg>
		<constructor-arg value="BeiJing"
			type="java.lang.String"></constructor-arg>
		<constructor-arg value="240" type="int"></constructor-arg>
	</bean>
</beans>

其它地方不用修改,重新运行一下测试代码,结果如下:

Car [brand=BMW, corp=BeiJing, price=0.0, maxSpeed=240]

这样就达到了我们想要的结果。
对于属性值的注入,还可以通过子节点下的value节点进行注入,效果是一样的。

引用类型属性值的注入

对字面值的注入有了一定的了解之后,我们单独看一下引用类型的属性值该如何注入:
先创建一个bean类:

package com.itcast.spring.bean;

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 + "]";
	}
}

在配置文件中配置一下Person类:

<?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="car2" class="com.itcast.spring.bean.Car">
		<constructor-arg value="BMW" type="java.lang.String"></constructor-arg>
		<constructor-arg value="BeiJing"
			type="java.lang.String"></constructor-arg>
		<constructor-arg value="240" type="int"></constructor-arg>
	</bean>
	
	<bean id="person" class="com.itcast.spring.bean.Person">
		<property name="name" value="Tony"></property>
		<property name="age" value="18"></property>
		<property name="car" ref="car2"></property>
	</bean>
</beans>

对于引用类型Car,我们可以通过property节点的ref属性指向对car的引用,因为上面我配置了一个id为car2的bean,所以这里直接通过id引用指向它。
编写测试代码:

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

运行效果:

Person [name=Tony, age=18, car=Car [brand=BMW, corp=BeiJing, price=0.0, maxSpeed=240]]

和上面类似,也可以使用子节点ref进行配置。

<bean id="person" class="com.itcast.spring.bean.Person">
		<property name="name" value="Tony"></property>
		<property name="age" value="18"></property>
		<property name="car">
			<ref bean="car2"/>
		</property>
</bean>

我们还可以在属性或构造器里包含一个bean的声明,这样的bean称为内部bean,无法被外部访问。

<bean id="person" class="com.itcast.spring.bean.Person">
		<property name="name" value="Tony"></property>
		<property name="age" value="18"></property>
		<property name="car">
			<bean class="com.itcast.spring.bean.Car">
				<constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
				<constructor-arg value="ShangHai" type="java.lang.String"></constructor-arg>
				<constructor-arg value="250000" type="double"></constructor-arg>
			</bean>
		</property>
</bean>

Spring和Struts、Hibernate框架一样,也支持级联属性。所以我们还可以通过级联属性赋值。

<property name="car.price" value="150000"></property>

可以通过这样的方式给Car类的属性赋值。

集合属性值注入

在引用类型中,又有一个特殊的群体,集合。包括Set、List、Map。
修改Person类代码:

package com.itcast.spring.bean;

import java.util.List;

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

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

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

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

其中有一个集合类型Car,该如何在配置文件中进行配置呢?

<?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="car" class="com.itcast.spring.bean.Car">
		<constructor-arg value="Audi"></constructor-arg>
		<constructor-arg value="ShangHai"></constructor-arg>
		<constructor-arg value="250000"></constructor-arg>
	</bean>

	<bean id="car2" class="com.itcast.spring.bean.Car">
		<constructor-arg value="BMW" type="java.lang.String"></constructor-arg>
		<constructor-arg value="BeiJing" type="java.lang.String"></constructor-arg>
		<constructor-arg value="240" type="int"></constructor-arg>
	</bean>
	
	<!-- 如何配置集合属性 -->
	<bean id="person2" class="com.itcast.spring.bean.Person">
		<property name="name" value="Jack"></property>
		<property name="age" value="20"></property>
		<property name="cars" >
			<list>
				<ref bean="car"/>
				<ref bean="car2"/>
			</list>
		</property>
	</bean>
</beans>

编写测试代码:

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

运行结果:

Person [name=Jack, age=20, cars=[Car [brand=Audi, corp=ShangHai, price=250000.0, maxSpeed=0], Car [brand=BMW, corp=BeiJing, price=150000.0, maxSpeed=240]]]

对于Set和Map集合,Spring提供了set标签和map标签进行配置,配置原理相同,不作重复介绍。Map集合会有点特殊,因为它是以键值对的方式存储的,所以它是通过Map节点下的子节点entry进行配置的,entry节点包含key和value-ref属性,也简单配置一下给大家看看吧。

<map>
	<entry key="aa" value-ref="car"></entry>
	<entry key="bb" value-ref="car2"></entry>
</map>

属性文件值注入

还有一种特殊类型,Properties,就是我们熟知的配置文件,在Spring中,同样可以通过配置直接将值注入到该属性中,看一个案例你们就会明白。
创建一个bane类:

package com.itcast.spring.bean;

import java.util.Properties;

public class DataSource {

	private Properties properties;

	public Properties getProperties() {
		return properties;
	}

	public void setProperties(Properties properties) {
		this.properties = properties;
	}

	@Override
	public String toString() {
		return "DataSource [properties=" + properties + "]";
	}
}

然后对该类进行配置:

<?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="dataSource" class="com.itcast.spring.bean.collection.DataSource">
		<property name="properties">
			<props>
				<prop key="user">root</prop>
				<prop key="password">123456</prop>
				<prop key="url">jdbc:mysql:///test</prop>
				<prop key="driver">com.mysql.jdbc.Driver</prop>
			</props>
		</property>
	</bean>
</beans>

配置完成后,编写测试代码:

public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		DataSource dataSource = (DataSource) ctx.getBean("dataSource");
		System.out.println(dataSource);
}

运行结果:

DataSource [properties={user=root, url=jdbc:mysql:///test, password=123456, driver=com.mysql.jdbc.Driver}]

实现过程非常简单,这样就将对数据库的配置注入到Properties属性中,关于对数据库的操作就可以通过这样进行封装。

鉴于是对Spring的快速入门,所以也没有去深入地介绍Spring的一些内容,关于Spring的快速入门,就说到这里,接下来还会出几篇Spring高级或者Spring一些其它的知识点。

posted @ 2019-08-26 11:28  ~wangweijun  阅读(269)  评论(0编辑  收藏  举报