Spring 是什么
- Spring 是一个开源框架.
- Spring 为简化企业级应用开发而生. 使用 Spring 可以使简单的 JavaBean 实现以前只有 EJB 才能实现的功能.
- Spring 是一个 IOC(DI) 和 AOP 容器框架.
具体描述Spring
- 轻量级:Spring 是非侵入性的 - 基于 Spring 开发的应用中的对象可以不依赖于 Spring 的 API
- 依赖注入(DI — dependency injection、IOC)
- 面向切面编程(AOP — aspect oriented programming)
- 容器: Spring 是一个容器, 因为它包含并且管理应用对象的生命周期
- 框架: Spring 实现了使用简单的组件配置组合成一个复杂的应用. 在 Spring 中可以使用 XML 和 Java 注解组合这些对象
- 一站式:在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方类库 (实际上 Spring 自身也提供了展现层的
SpringMVC 和 持久层的 Spring JDBC)
IOC 和 DI
- IOC(Inversion of Control):其思想是反转资源获取的方向. 传统的资源查找方式要求组件向容器发起请求查找资源.作为回应, 容器适时的返回资源. 而应用了 IOC 之后, 则是容器主动地将资源推送给它所管理的组件,组件所要做的仅是选择一种合适的方式来接受资源. 这种行为也被称为查找的被动形式
- DI(Dependency Injection) — IOC 的另一种表述方式:即组件以一些预先定义好的方式(例如: setter 方法)接受来自如容器的资源注入. 相对于 IOC 而言,这种表述更直接
IOC 容器
- 在 Spring IOC 容器读取 Bean 配置创建 Bean 实例之前, 必须对它进行实例化. 只有在容器实例化后, 才可以从 IOC 容器里获取 Bean 实例并使用.
- Spring 提供了两种类型的 IOC 容器实现.
- BeanFactory: IOC 容器的基本实现.
- ApplicationContext: 提供了更多的高级特性. 是 BeanFactory 的子接口.
- BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的应用场合都直接使用 ApplicationContext 而非底层的 BeanFactory
- 无论使用何种方式, 配置文件是相同的.
开发环境的搭建
需要 jar 包
commons-logging-1.1.1.jar
spring-beans-4.0.2.RELEASE.jar
spring-context-4.0.2.RELEASE.jar
spring-core-4.0.2.RELEASE.jar
spring-expression-4.0.2.RELEASE.jar
Spring bean 的配置细节
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"
xmlns:p="http://www.springframework.org/schema/p"
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">
<!--
配置 bean
class: bean 的全类名, 通过反射的方法在 IOC 容器中创建 Bean, 使用必须要求有无参构造函数
id: 标识容器中的 bean, id 唯一
-->
<bean id="hellospring" class="com.anqi.hello.HelloSpring">
<property name="name" value="anqi"></property>
</bean>
<!-- 通过构造方法来配置 bean 的属性 -->
<bean id="car" class="com.anqi.hello.Car">
<constructor-arg value="Audi" index="0"></constructor-arg>
<constructor-arg value="Shanghai" index="1"></constructor-arg>
<constructor-arg value="300000" index="2"></constructor-arg>
</bean>
<!-- 使用构造器注入属性值可以指定参数的位置和参数的类型! 以区分重载的构造器! -->
<bean id="car2" class="com.anqi.hello.Car">
<constructor-arg value="Baoma" index="0"></constructor-arg>
<constructor-arg value="Shanghai" index="1"></constructor-arg>
<constructor-arg value="240" type="int"></constructor-arg>
</bean>
<bean id="car3" class="com.anqi.hello.Car">
<constructor-arg value="Baoma3" index="0"></constructor-arg>
<!-- 如果字面值包含特殊字符 可以用<![CDATA[]]> 包裹起来 -->
<!-- 字面值就是基本数据类型及其包装类, 以及 String 类 -->
<!-- 属性值也可以使用 value 节点来进行配置 -->
<constructor-arg index="1">
<value><![CDATA[<shanghai3]]></value>
</constructor-arg>
<constructor-arg value="2403" type="int"></constructor-arg>
</bean>
<bean id = "person" class = "com.anqi.hello.Person">
<property name="name" value="Anqi"></property>
<property name="age">
<value>25</value>
</property>
<!-- <property name="car" ref="car2"></property> 与下面代码效果一致-->
<!--
<property name="car">
<ref bean="car2"/>
</property>
-->
<!-- 内部 bean 不能被外部引用, 只能在内部使用-->
<property name="car">
<bean class="com.anqi.hello.Car">
<constructor-arg value="fute"></constructor-arg>
<constructor-arg value="Beijing"></constructor-arg>
<constructor-arg value="28000" type="double"></constructor-arg>
</bean>
</property>
</bean>
<bean id="person2" class="com.anqi.hello.Person">
<constructor-arg value="LiChen"></constructor-arg>
<constructor-arg value="18"></constructor-arg>
<!-- 测试赋值 NULL 值 -->
<!--<constructor-arg><null/></constructor-arg> -->
<constructor-arg name="car" ref="car2"></constructor-arg>
<!-- 为级联属性赋值,必须有对应的 setter 方法 -->
<!-- 注意 : 属性需要先初始化后才可以为级联属性赋值, 否则会有异常 -->
<property name="car.maxSpeed" value="220"></property>
</bean>
<bean id="person3" class="com.anqi.hello.collections.Person">
<property name="name" value="Angels"></property>
<property name="age" value="23"></property>
<property name="cars">
<!-- 使用 list 节点来为 List 类型的属性赋值 -->
<list>
<ref bean="car"/>
<ref bean="car2"/>
<bean class="com.anqi.hello.Car">
<constructor-arg value="fute2"></constructor-arg>
<constructor-arg value="Beijing2"></constructor-arg>
<constructor-arg value="280002" type="double"></constructor-arg>
</bean>
</list>
</property>
</bean>
<!-- 配置 Map 属性值 -->
<bean id="newPerson" class="com.anqi.hello.collections.NewPerson">
<property name="name" value='ANAN'></property>
<property name="age" value="18"></property>
<property name="cars">
<!-- 使用 map 节点及 map 的 entry 子节点配置 Map 类型的成员变量 -->
<map>
<entry key="AA" value-ref="car2"></entry>
<entry key="BB" value-ref="car3"></entry>
</map>
</property>
</bean>
<!-- 配置 Properties 属性值 -->
<bean id="datasource" class="com.anqi.hello.collections.DataSource">
<property name="properties">
<!-- 使用 props 和 prop 子节点为 Properties 属性赋值 -->
<props>
<prop key="user">root</prop>
<prop key="password">12345</prop>
<prop key="jdbcUrl">jdbc:mysql:///javaee</prop>
<prop key="driverManger">com.mysql.jdbc.Driver</prop>
</props>
</property>
</bean>
<!-- 配置独立的集合 bean, 以供多个 bean 进行引用, 需要导入 utill 命名空间 -->
<!-- 使用不带版本号的 util 命名空间,否则会报错 -->
<util:list id="cars">
<ref bean="car"/>
<ref bean="car2"/>
</util:list>
<bean id="person4" class="com.anqi.hello.collections.Person">
<property name="name" value="anyixuan"></property>
<property name="age" value="5"></property>
<property name="cars" ref="cars"></property>
</bean>
<!-- 通过 p 命名空间为 bean 的属性赋值, 需要先导入 p 命名空间, 相对于传统的配置方式更加的简洁。 -->
<bean id="person5" class="com.anqi.hello.collections.Person" p:age="30" p:name="Queen"
p:cars-ref="cars">
</bean>
</beans>
Car.java
package com.anqi.hello;
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;
}
//....setter getter toString
}
Person.java
package com.anqi.hello;
public class Person {
private String name;
private int age;
private Car car;
public Person(String name, int age, Car car) {
super();
this.name = name;
this.age = age;
this.car = car;
}
public Person() {
super();
//....setter getter toString
}
Main.java
package com.anqi.hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
//1. 创建 Spring 的 IOC 容器对象
//ApplicationContext 代表 IOC 容器
//ClassPathXmlAppolicationContext : ApplicationContext 接口的实现类,该实现类从类路径下来加载文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2. 从 IOC 容器中获取 Bean 的实例
//利用 id 定位到 IOC 容器中的 Bean
HelloSpring helloSpring = (HelloSpring) ctx.getBean("hellospring");
//利用类型返回 IOC 容器中的 Bean, 但要求 IOC 容器中必须只能有一个该类型的 Bean
//HelloSpring helloSpring = ctx.getBean(HelloSpring.class);
//3. 调用 hello 方法
helloSpring.hello();
Car car = (Car) ctx.getBean("car");
System.out.println(car);
//Car [brand=Audi, corp=Shanghai, price=300000.0, maxSpeed=0]
car = (Car) ctx.getBean("car2");
System.out.println(car);
//Car [brand=Baoma, corp=Shanghai, price=0.0, maxSpeed=240]
car = (Car) ctx.getBean("car3");
System.out.println(car);
//Car [brand=Baoma3, corp=<shanghai3, price=0.0, maxSpeed=2403]
Person p = (Person) ctx.getBean("person");
System.out.println(p);
//Person [name=Anqi, age=25, car=Car [brand=Baoma, corp=Shanghai, price=0.0, maxSpeed=240]]
p = (Person) ctx.getBean("person2");
System.out.println(p);
//Person [name=LiChen, age=18, car=Car [brand=Baoma, corp=Shanghai, price=0.0, maxSpeed=220]]
}
}
com.anqi.hello.collections 下的
Person.java
package com.anqi.hello.collections;
import java.util.List;
import com.anqi.hello.Car;
public class Person {
private String name;
private int age;
private List<Car> cars;
public Person(String name, int age, List<Car> cars) {
super();
this.name = name;
this.age = age;
this.cars = cars;
}
public Person() {
super();
}
//....setter getter toString
}
NrePerson.java
package com.anqi.hello.collections;
import java.util.Map;
import com.anqi.hello.Car;
public class NewPerson {
private String name;
private int age;
private Map<String, Car> cars;
public NewPerson(String name, int age, Map<String, Car> cars) {
super();
this.name = name;
this.age = age;
this.cars = cars;
}
public NewPerson() {
super();
}
//....setter getter toString
}
DataSource.java
package com.anqi.hello.collections;
import java.util.Properties;
public class DataSource {
private Properties properties;
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public String toString() {
return "DataSource [properties=" + properties + "]";
}
}
Main.java
package com.anqi.hello.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 person3 = (Person) ctx.getBean("person3");
System.out.println(person3);
//Person [name=Angels, age=23, cars=[Car [brand=Audi, corp=Shanghai, price=300000.0, maxSpeed=0],
//Car [brand=Baoma, corp=Shanghai, price=0.0, maxSpeed=220], Car [brand=fute2, corp=Beijing2,
//price=280002.0, maxSpeed=0]]]
NewPerson newPerson = (NewPerson) ctx.getBean("newPerson");
System.out.println(newPerson);
//NewPerson [name=ANAN, age=18, cars={AA=Car [brand=Baoma, corp=Shanghai, price=0.0, maxSpeed=220],
//BB=Car [brand=Baoma3, corp=<shanghai3, price=0.0, maxSpeed=2403]}]
DataSource dataSource = (DataSource) ctx.getBean("datasource");
System.out.println(dataSource);
//DataSource [properties={user=root, password=12345, driverManger=com.mysql.jdbc.Driver,
//jdbcUrl=jdbc:mysql:///javaee}]
Person person4 = (Person) ctx.getBean("person4");
System.out.println(person4);
//Person [name=anyixuan, age=5, cars=[Car [brand=Audi, corp=Shanghai, price=300000.0, maxSpeed=0],
//Car [brand=Baoma, corp=Shanghai, price=0.0, maxSpeed=220]]]
Person person5 = (Person) ctx.getBean("person5");
System.out.println(person5);
//Person [name=Queen, age=30, cars=[Car [brand=Audi, corp=Shanghai, price=300000.0, maxSpeed=0],
//Car [brand=Baoma, corp=Shanghai, price=0.0, maxSpeed=220]]]
}
}