Spring学习(一)
Spring特点轻量级:Spring 是非侵入性的 - 基于 Spring 开发的应用中的对象可以不依赖于 Spring 的 API依赖注入(DI — dependency injection、IOC)面向切面编程(AOP — aspect oriented programming)容器: Spring 是一个容器, 因为它包含并且管理应用对象的生命周期框架: Spring 实现了使用...
Spring特点
轻量级:Spring 是非侵入性的 - 基于 Spring 开发的应用中的对象可以不依赖于 Spring 的 API
依赖注入(DI — dependency injection、IOC)
面向切面编程(AOP — aspect oriented programming)
容器: Spring 是一个容器, 因为它包含并且管理应用对象的生命周期
框架: Spring 实现了使用简单的组件配置组合成一个复杂的应用. 在 Spring 中可以使用 XML 和 Java 注解组合这些对象
一站式:在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方类库 (实际上 Spring 自身也提供了展现层的 SpringMVC 和 持久层的 Spring JDBC)
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">
<!--
class:bean的全类名,通过反射的方式在在IoC容器中创建bean,所以要求bean中应有一个无参构造方法;
id(name):用于标识bean,也可用name表示;在同一个容器中,id应该是惟一的;id名称一般是类名第一个字母小写;
-->
<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容器
BeanFactory接口
IoC容器的基本实现,定义了IoC容器最基本的功能,所有的Spring IoC容器都是在这个接口的基础上实现的
ApplicationContext
提供了更多的高级特性,是BeanFactory的子接口
ApplicationContext的主要实现类
类名 | 作用 |
---|---|
ClassPathXmlApplicationContext | 从 类路径下加载配置文件 |
FileSystemXmlApplicationContext | 从文件系统中加载配置文件 |
ConfigurableApplicationContext | 扩展于 ApplicationContext,新增加两个主要方法:refresh() 和 close(), 让 ApplicationContext 具有启动、刷新和关闭上下文的能力 |
WebApplicationContext | 专门为 WEB 应用而准备的,它允许从相对于 WEB 根目录的路径中完成初始化工作 |
获取Bean的方式
通过id(name)
@Test
public void getBeanByName(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorld helloWorld = (HelloWorld) applicationContext.getBean("helloWorld");
helloWorld.hello();
}
通过bean的类型
@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)
属性注入的方式
Setter方法注入
需要在类中为属性都写上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>
特殊字符与null值
<!--特殊字符值的注入-->
<bean class="beans.Person" id="person">
<property name="name" value="![DATA][<张三>]"></property>
<property name="age" value="![DATA][<null/>]"></property>
</bean>
嵌套注入
<bean class="beans.Person" id="person3">
<constructor-arg index="0">
<!--直接配置一个bean作为属性,该bean不可以被其他bean引用-->
<bean class="beans.Car" >
<constructor-arg value="baoma" index="0"></constructor-arg>
<constructor-arg value="1000000" index="1"></constructor-arg>
</bean>
</constructor-arg>
</bean>
集合类型
List
<!--集合类型list-->
<bean class="beans.Student" id="student">
<property name="cars">
<list>
<ref bean="car"></ref>
<ref bean="car2"></ref>
</list>
</property>
</bean>
Map
<!--集合类型map-->
<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>
将集合类型配置为bean,以供其他bean引用
<!--集合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
<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='顺丰街'}
- 父 Bean 可以作为配置模板, 也可以作为 Bean 实例. 若只想把父 Bean 作为模板, 可以设置 的abstract 属性为 true, 这样 Spring 将不会实例化这个 Bean
- 并不是 元素里的所有属性都会被继承. 比如: autowire, abstract 等.
- 也可以忽略父 Bean 的 class 属性, 让子 Bean 指定自己的类, 而共享相同的属性配置. 但此时 abstract 必须设为 true
现在加上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
<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}}
- 如果我们想要在进行实例化person之间必须先实例化他的car属性,则可以通过depends-on参数来设置,Spring 允许用户通过 depends-on 属性设定 Bean 前置依赖的Bean,前置依赖的 Bean 会在本 Bean 实例化之前创建好
- 如果前置依赖于多个 Bean,则可以通过逗号,空格或的方式配置 Bean 的名称
<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的作用域
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());
}
更多推荐
所有评论(0)