轻量级:Spring 是非侵入性的 - 基于 Spring 开发的应用中的对象可以不依赖于 Spring 的 API
依赖注入(DI — dependency injection、IOC)
面向切面编程(AOP — aspect oriented programming)
容器: Spring 是一个容器, 因为它包含并且管理应用对象的生命周期
框架: Spring 实现了使用简单的组件配置组合成一个复杂的应用. 在 Spring 中可以使用 XML 和 Java 注解组合这些对象
一站式:在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方类库 (实际上 Spring 自身也提供了展现层的 SpringMVC 和 持久层的 Spring JDBC)
<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 class="beans.HelloWorld" id="helloWorld">
<property name="name" value="Spring">property>
bean>
beans>
POJO类
package beans;
/**
* @author
* @Description: Spring-HelloWorld
* @date 2018/12/6下午10:12
**/
public class HelloWorld {
public HelloWorld() {
}
public HelloWorld(String name) {
this.name = name;
}
private String name;
public void hello(){
System.out.println("hello:"+getName());
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
测试
@Test
public void getBeanByName(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorld helloWorld = (HelloWorld) applicationContext.getBean("helloWorld");
helloWorld.hello();
}
IoC容器的基本实现,定义了IoC容器最基本的功能,所有的Spring IoC容器都是在这个接口的基础上实现的
提供了更多的高级特性,是BeanFactory的子接口
类名 | 作用 |
---|---|
ClassPathXmlApplicationContext | 从 类路径下加载配置文件 |
FileSystemXmlApplicationContext | 从文件系统中加载配置文件 |
ConfigurableApplicationContext | 扩展于 ApplicationContext,新增加两个主要方法:refresh() 和 close(), 让 ApplicationContext 具有启动、刷新和关闭上下文的能力 |
WebApplicationContext | 专门为 WEB 应用而准备的,它允许从相对于 WEB 根目录的路径中完成初始化工作 |
@Test
public void getBeanByName(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorld helloWorld = (HelloWorld) applicationContext.getBean("helloWorld");
helloWorld.hello();
}
@Test
public void getBeanByType(){
// 当applicationContext配置文件中同时存在两个同类型的bean时,这样获取会报错
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Car car = applicationContext.getBean(Car.class);
System.out.println(car.toString());
}
报错信息
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [beans.Car] is defined: expected single matching bean but found 2: car,car2
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:312)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:985)
at beans.Main.getBeanByType(Main.java:25)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
需要在类中为属性都写上getter和setter方法
<bean class="beans.HelloWorld" id="helloWorld">
<property name="name" value="Spring">property>
bean>
<bean class="beans.Car" id="car">
<constructor-arg value="baoma" index="0">constructor-arg>
<constructor-arg value="1000000" index="1">constructor-arg>
bean>
<bean class="beans.Car" id="car2">
<constructor-arg value="benchi" type="java.lang.String">constructor-arg>
<constructor-arg value="120.5" type="java.lang.Double">constructor-arg>
bean>
使用value进行注入
<bean class="beans.HelloWorld" id="helloWorld">
<property name="name" value="Spring">property>
bean>
使用ref进行注入
<bean class="beans.Person" id="person">
<property name="car" ref="car">property>
bean>
<bean class="beans.Person" id="person">
<property name="name" value="![DATA][<张三>]">property>
<property name="age" value="![DATA][ ]">property>
bean>
<bean class="beans.Person" id="person3">
<constructor-arg index="0">
<bean class="beans.Car" >
<constructor-arg value="baoma" index="0">constructor-arg>
<constructor-arg value="1000000" index="1">constructor-arg>
bean>
constructor-arg>
bean>
<bean class="beans.Student" id="student">
<property name="cars">
<list>
<ref bean="car">ref>
<ref bean="car2">ref>
list>
property>
bean>
<bean class="beans.NewPerson" id="newPerson">
<property name="carMap">
<map>
<entry key="aa">
<ref bean="car">ref>
entry>
<entry key="bb" value-ref="car2">entry>
map>
property>
bean>
<util:list id="listFactoryBean">
<ref bean="car">ref>
<ref bean="car2">ref>
util:list>
<bean class="beans.Student" id="student2">
<property name="cars">
<ref bean="listFactoryBean">ref>
property>
bean>
<util:map id="map">
<entry key="aa">
<ref bean="car">ref>
entry>
<entry key="bb" value-ref="car2">entry>
util:map>
<bean class="beans.NewPerson" id="newPerson2">
<property name="carMap">
<ref bean="map">ref>
property>
bean>
我们先来观察以下两个bean
<bean class="beans.Address" id="address" p:city="周口" p:address="大庆路" abstract="true">bean>
<bean class="beans.Address" id="address2" p:city="周口" p:address="建设路">bean>
可以发现,两个bean除了address属性不同,其余属性都是相同的,如果按照这样配置的话,会显得有点麻烦,因此我们可以使用parent参数来完成bean之间的继承
<bean class="beans.Address" id="address" p:city="周口" p:address="大庆路" abstract="true">bean>
<bean class="beans.Address" id="address3" parent="address" p:address="顺丰街">bean>
现在测试一下
@Test
public void testBeanExtends(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Address address = (Address) applicationContext.getBean("address3");
System.out.println(address);
}
// 输出:Address{city='周口', address='顺丰街'}
现在加上abstract="true"进行测试
<bean class="beans.Address" id="address" p:city="周口" p:address="大庆路" abstract="true">bean>
<bean class="beans.Address" id="address3" parent="address" p:address="顺丰街">bean>
@Test
public void testBeanExtends(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Address parent = (Address) applicationContext.getBean("address");
}
会出现如下报错:应为加了abstract属性的bean不会被Spring容器实例化
org.springframework.beans.factory.BeanIsAbstractException: Error creating bean with name 'address': Bean definition is abstract
假设我们现在有以下一个bean
<bean class="beans.Person" id="person">
<property name="car" ref="car">property>
bean>
<bean class="beans.Car" id="car">
<constructor-arg value="baoma" index="0">constructor-arg>
<constructor-arg value="1000000" index="1">constructor-arg>
bean>
进行测试可以得到如下结果
@Test
public void testRef(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) applicationContext.getBean("person");
System.out.println(person.toString());
}
// 输出:Person{car=Car{name='baoma', price=1000000, maxSpeed=null}}
<bean class="beans.Person" id="person" depends-on="car">
<property name="car" ref="car">property>
bean>
<bean class="beans.Car" id="car">
<constructor-arg value="baoma" index="0">constructor-arg>
<constructor-arg value="1000000" index="1">constructor-arg>
bean>
在设置这个参数之后入门实例化person时没有实例化car,则会报错
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'car' is defined
Spring默认创建的bean都是单例的,当我们使用ApplicationContext.getBaen(name)方法时,Spring会先在容器里查找有没有已经创建该bean,若创建了则直接返回,没有就新建一个。现在我们进行测试验证:
配置文件
<bean class="beans.Person" id="person">
<property name="car" ref="car">property>
bean>
测试代码
@Test
public void testScope(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person1 = (Person) applicationContext.getBean("person");
Person person2 = (Person) applicationContext.getBean("person");
System.out.println(person1==person2);
}
// 输出结果为:true,说明默认的bean是单例的
若我们想创建多例的bean则可以使用scope参数,该参数默认值为singleton(单例),创建多例bean可以将该参数的值改为scope=“propotype”。在进行测试
配置文件
<bean class="beans.Person" id="person" scope="prototype">
<property name="car" ref="car">property>
bean>
测试代码
@Test
public void testScope(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person1 = (Person) applicationContext.getBean("person");
Person person2 = (Person) applicationContext.getBean("person");
System.out.println(person1==person2);
}
// 输出结果为:false,说明该bean是多例的
在我们开发应用程序的时候难免需要与其他程序(如数据库)进行连接,如果我们将连接信息配置在spring的配置文件中就会导致后序的修改变得很麻烦,因此我们需要将信息写入外部属性文件,然后再spring里在进行链接。
db.properties
username=root
password=123
driverClass = com.mysql.jdbc.Driver
jdbcUrl = jdbc:mysql:///rtlzz
applicationContext.xml
<context:property-placeholder location="db.properties">context:property-placeholder>
<bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="dataSource">
<property name="user" value="${username}">property>
<property name="password" value="${password}">property>
<property name="driverClass" value="${driverClass}">property>
<property name="jdbcUrl" value="${jdbcUrl}">property>
bean>
beans>
测试类
@Test
public void testConnection() throws SQLException {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("base-properties.xml");
DataSource dataSource = (DataSource) applicationContext.getBean("dataSource");
System.out.println(dataSource.getConnection());
}