spring IOC 详解
Hello World
HelloWorld.java
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package com.test.spring01;public class HelloWorld { private String name; public HelloWorld() { System.out.println("调用构造函数..."); } public String getName() { return name; } public void setName2(String name) {//对应name="name2" this.name = name; } public void sayHello() { System.out.println("Hello," + name); }} |
Main.java
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
package com.test.spring01;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Main { public static void main(String[] args) { //ClassPathXmlApplicationContext是ApplicationContext接口的实现类,实现从类路径下加载配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml"); System.out.println("创建对象"); HelloWorld helloWorld = (HelloWorld)applicationContext.getBean("a1"); //HelloWorld helloWorld = applicationContext.getBean(HelloWorld.class); //这种方式要求在配置文件中只配置了一个HelloWorld的bean helloWorld.sayHello(); }} |
applicationContext.xml
|
1
2
3
4
5
6
7
8
9
10
11
12
|
<?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-3.0.xsd"> <bean id="a1" class="com.test.spring01.HelloWorld"> <property name="name2" value="spring"/> <!--set方法注入--> </bean></beans> |
运行结果
调用构造函数...
创建对象
Hello,spring
也可以通过构造方法注入
|
1
2
3
4
5
6
|
<!--通过构造方法来配置bean属性--><bean id="car" class="com.atguigu.spring.beans.Car"><!--参数和构造函数的参数对应--> <constructor-arg value="Audi" index="0"></constructor-arg> <constructor-arg value="Shanghai" index="1"></constructor-arg> <constructor-arg value="300000" type="double"></constructor-arg></bean> |
|
1
2
3
4
5
6
|
<!--使用构造器注入属性值可以指定参数的位置和参数的类型,以区分重载的构造器--><bean id="car2" class="com.atguigu.spring.beans.Car"> <constructor-arg value="Baoma" type="java.lang.String"></constructor-arg> <constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg> <constructor-arg value="400000" type="int"></constructor-arg></bean> |
有特殊标记时也可以下面这么写
|
1
2
3
4
5
6
7
8
9
|
<bean id="car2" class="com.atguigu.spring.beans.Car"> <constructor-arg value="Baoma" type="java.lang.String"></constructor-arg> <constructor-arg type="java.lang.String"> <value><![CDATA[<Shanghai^>]]></value> </constructor-arg> <constructor-arg type="int"> <value>400000</value> </constructor-arg></bean> |
引用类型
|
1
2
3
4
5
|
<bean id="person" class="com.atguigu.spring.beans.Person"> <property name="name" value="Tom"></property> <property name="age" value="34"></property> <property name="car" ref="car2"></property><!--引用car2--></bean> |
内部bean,不能被外部引用,只能在内部使用
|
1
2
3
4
5
6
7
8
|
<!--内部bean--><property name="car"><!--上面的car可以这么写--> <bean class="com.atguigu.spring.beans.Car"> <constructor-arg value="Ford"></constructor-arg> <constructor-arg value="Changan"></constructor-arg> <constructor-arg value="200000" type="double"></constructor-arg> </bean></property> |
赋null值
|
1
2
|
<!--测试值赋null--><constructor-arg><null/></constructor-arg> |
为级联属性赋值(必须有set方法) 要先创建car才能赋值
|
1
2
3
|
<constructor-arg ref="car"></constructor-arg><!--为级联属性赋值--><property name="car.macSpeed" value="240"></property> |
为集合属性赋值(list set map)
|
1
2
3
4
5
6
7
8
9
10
|
<bean id="person3" class="com.atguigu.spring.collections.Person"> <property name="name" value="Tom"></property> <property name="age" value="34"></property> <property name="cars"><!--cars是Person类的一个list类型的属性--> <list> <ref bean="car"> <ref bean="car2"> </list> </property></bean> |
|
1
2
3
4
5
6
7
8
9
10
11
|
<!--配置Map属性值--><bean id="person4" class="com.atguigu.spring.collections.Person"> <property name="name" value="Tom"></property> <property name="age" value="34"></property> <property name="cars"><!--cars是Person类的一个map类型的属性--> <map> <entry key="AA" value-ref="car"></entry> <entry key="BB" value-ref="car2"></entry> </map> </property></bean> |
|
1
2
3
4
5
6
7
8
9
10
11
|
<!--配置Peoperties属性值--><bean id="dataSource" class="com.atguigu.spring.collections.dataSource"> <property name="peoperties"> <props> <prop key="user">root</prop> <prop key="password">123456</prop> <prop key="jdbcUrl">jdbc:mysql:///test</prop> <prop key="driverClass">com.mysql.jdbc.Driver</prop> </props> </property></bean> |
|
1
2
3
4
5
6
7
8
9
10
|
<!--配置单例的集合bean,以供多个bean进行引用,需要导入util命名空间--><util:list id="cars"> <ref bean="car"> <ref bean="car2"></util:list><bean id="person4" class="com.atguigu.spring.collections.Person"> <property name="name" value="Jack"></property> <property name="age" value="29"></property> <property name="cars" ref="cars"></property><!--引用上面配置的cars--></bean> |
|
1
2
3
|
<!--通过P命名空间为bean的属性赋值,需要先导入P命名空间--><bean id="person5" class="com.atguigu.spring.collections.Person" p:age="35" p:name="Shang" p:cars-ref="cars"></bean> |
自动装配(Person类中有address属性和car属性)
byName根据bean的名字和当前bean的setter风格的属性名进行自动装配。
byType根据bean的类型和当前bean的数学的类型进行自动装配。(如果有两个类型一样的bean就会出错)
缺点:在bean配置文件里设置autowire属性进行自动装配将会装配bean的所有属性。若只希望装配个别属性时,autowire属性就不够灵活了。autowire属性要么根据类型自动装配,要么根据名称自动装配,不能两者兼而有之。
一般情况下,在是寄到 项目中很少使用自动装配功能,因为和自动装配功能所带来的好处比起来,明确清晰的配置文档更有说服力一些。
|
1
2
3
4
5
|
<bean id="address" class="com.atguigu.spring.beans.autowire.Address" p:city="Beijing" p:street="Huilongguan"></bean><bean id="car" class="com.atguigu.spring.beans.autowire.Car" p:brand="Audi" p:price="30000"></bean><bean id="person" class="com.atguigu.spring.beans.autowire.Person" p:name="Tom" p:autowire="byName"></bean> |
bean配置的继承
|
1
2
3
4
|
<bean id="address" class="com.atguigu.spring.beans.autowire.Address" p:city="Beijing" p:street="Wudaokou"></bean><!--bean配置的继承:使用bean的parent属性指定继承哪个bean的配置--><bean id="address2" p:street="Dazhongsi" parent="address"></bean> |
抽象bean,只能被继承
|
1
2
3
4
|
<!--抽象bean:bean的abstract属性为true的bean,不能被IOC容器实例化若一个bean的class属性没有指定,则该bean必须是一个抽象的bean。类似抽象类--><bean id="address" p:city="Beijing" p:street="Wudaokou" abstract="true"></bean> |
bean之间的依赖关系
Spring允许用户通过depends-on属性设定Bean前置依赖的Bean,前置依赖的Bean会在本Bean实例化之前创建好。如果前置依赖于多个Bean,则可以通过逗号、空格的方式配置多个Bean。
|
1
2
3
|
<bean id="car" class="com.atguigu.spring.autowire.Car" p:brand="Audi" p:price="30000"></bean><!--要求在配置person时,必须有一个关联的car。person这个bean依赖于car这个bean--><bean id="person" class="som.atguigu.spring.beans.autowire.Person" p:name="Tom" p:address-ref="address2" depends-on="car"></bean> |
bean配置的作用域
默认为单例singleton,容器初始化时创建bean实例,在整个容器的生命周期里只创建一个bean。
prototype原型,容器初始化时不创建bean实例,在每次请求时创建一个新的bean实例并返回。
|
1
2
3
4
|
<bean id="car" class="com.atguigu.spring.autowire.Car" scope="prototype"> <property name="brand" value="Audi"></property> <property name="price" value="300000"></property></bean> |
引入外部配置文件
不引入配置文件时这么写. beans-properties.xml
|
1
2
3
4
5
6
|
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="root"></property> <property name="password" value="123456"></property> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql:///test"></property></bean> |
|
1
2
3
|
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-properties.xml");DataSource dataSource = (DataSource)ctx.getBean("dataSource");System.out.println(dataSource.getConnection());//建立连接 |
引入外部配置文件
db.properties
|
1
2
3
4
|
user=rootpassword=123456driverClass=com.mysql.jdbc.DriverjdbcUrl=jdbc:mysql:///test |
beans-properties.xml写法
|
1
2
3
4
5
6
7
8
|
<!--导入属性文件--><!--要导入context命名空间--><context:property-placeholder location="classpath:db.properties"/><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${user}"></property> <property name="password" value="${password}"></property> <property name="driverClass" value="${driverClass}"></property> <property name="jdbcUrl" value="${jdbcUrl}"></property></bean> |
Spring表达式语言:SpEL。支持运行时查询和操作对象。
字面量的表示
整数
|
1
|
<property name="count" value="#{5}"/> |
小数
|
1
|
<property name="frequency" value="#{89.7}"/> |
科学计数法
|
1
|
<property name="capacity" value="1e4"/> |
String可以使用单引号或者双引号作为字符串的定界符号
|
1
2
|
<property name="name" value="#{'chuck'}"/><property name="name" value='#{"chuck"}'/> |
Boolean
|
1
|
<property name="enabled" value="#{false}"/> |
引用其他对象,等同ref
|
1
2
|
<!--通过value属性和SpEL配置bean之间的引用关系--><property name="prefix" value="#{prefixGernerator}"/> |
引用其他对象的属性
|
1
|
<property name="suffix" value="#{prefixGernerator.suffix}"/> |
调用其他方法,还可以链式操作
|
1
|
<property name="suffix" value="#{prefixGernerator.toString()}"/> |
|
1
2
|
<!---方法的连缀--><property name="suffix" value="#{prefixGernerator.toString().toUpperCase()}"/> |
|
1
|
<property name="price" value="#{T(java.jang.Math).PI*80}"></property> |
|
1
2
3
4
5
6
|
<!--使用SpEL表达式来引用其他的bean--><property name="car" value="#{car}"></property><!--使用SpEL表达式来引用其他的bean的属性--><property name="city" value="#{address.city}"></property><!--在SpEL中使用运算符--><property name="info" value="#{car.price>300000?'金玲':'白领'}"></property> |
为bean指定init方法和destroy方法
|
1
2
3
4
5
|
<bean id="car" class="com.atguigu.spring.bean.Car"init-method="init" destroy-method="destroy"><!--init和destroy对应Car类中的init destroy方法--> <property name="brand" value="Audi"></property></bean><!--setBrand之后调用init方法,ctx.close();时调用destroy方法--> |
Bean后置处理器允许在调用初始化方法前后对bean进行额外的处理。Bean后置处理器对IOC容器里的所有的Bean实例逐一处理,而非单一实例。其典型应用是:检查Bean属性的正确性或根据特定的标准更改Bean属性。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class MyBeanPostProcessor implements BeanPostProcessor{ //处理所有bean @override public Object postProcessBeforeInitialization(Object bean, Stirng beanName)throws BeansException{ //可以在这里进行一些操作 if("car".equals(beanName)){ //... } System.out.println("postProcessBeforeInitialization..."); return bean; } @override public Object postProcessAfterInitialization(Object bean, Stirng beanName)throws BeansException{ System.out.println("postProcessAfterInitialization..."); //可以在这里对bean的属性进行更改...安全隐患 return bean; }} |
|
1
2
3
4
5
6
7
8
9
10
|
<!--配置文件中配置bean的后置处理器。不需要配置id,IOC容器自动识别是一个BeanPostProcessor--><!--实现BeanPostProcessor接口,并且提供实现Object postProcessBeforeInitialization(Object bean, Stirng beanName) init-method之前调用Object postProcessAfterInitialization(Object bean, Stirng beanName) init-method之后调用bean: bean实例本身beanName:IOC容器配置的bwan的名字返回值:实际上返回给用户的bean。可以在以上两个方法中修改返回的bean,甚至返回一个新的bean--><bean class="com.atguigu.spring.MyBeanPostProcessor"></bean> |
Spring IOC容器对Bean的生命周期进行管理的过程
-通过构造器或工厂方法创建Bean实例
-为bean的属性设置值和对其他bean的引用
-将bean实例传递给bean后置处理器的postProcessBeforeInitialization方法
-调用bean的初始化方法
-将bean实例传递给bean后置处理器的postProcessAfterInitialization方法
-bean可以使用了
-容器关闭时,调用bean的销毁方法
静态工厂方法
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
/***静态工厂方法:直接调用某一个类的静态方法就可以返回bean的实例*/public class StaticCarFactory{ private static Map<String, car> cars = new HashMap<String, Car>(); static{ cars.put("audi", new Car("audi", 300000)); cars.put("ford", new Car("ford", 400000)); } //静态工厂方法 public static Car getCar(String name){ return cars.get(name); }} |
|
1
2
3
4
5
6
7
8
9
10
11
|
<!--通过静态工厂方法来配置bean--><!-- class属性:指向静态工程方法的全类名 factory-method:静态工厂方法的名字 constructor-arg:如果工厂方法需要传入参数,使用constructor-arg来配置参数--><bean id="car1" class="com.atguigu.spring.StaticCarFactory" factory-method="getCar"> <constructor-arg value="audi"></constructor-arg></bean> |
|
1
|
Car car = (Car)ctx.getBean("car1");//取对象 |
实例工厂方法
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/***实例工厂方法,即先需要创建工厂,然后调用工厂的实例方法来返回bean的实例*/public class InstanceCarFactory{ private Map<String, car> cars = null; public InstanceCarFactory(){ cars = new HashMap<String, Car>(); cars.put("audi", new Car("audi", 300000)); cars.put("ford", new Car("ford", 400000)); } public Car getCar(String name){ return cars.get(name); }} |
|
1
2
3
4
5
6
7
8
9
10
|
<bean id="carFactory" class="com.atguigu.spring.InstanceCarFactory"></bean><!--通过实例工厂方法来配置bean--><!-- factory-bean属性:指向实例工程方法的全类名 factory-method:方法的名字 constructor-arg:如果工厂方法需要传入参数,使用constructor-arg来配置参数--><bean id="car2" factory-bean="carFactory" factory-method="getCar"> <constructor-arg value="audi"></constructor-arg></bean> |
|
1
|
Car car = (Car)ctx.getBean("car2");//取对象 |
通过FactoryBean配置Bean
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public class CarFactoryBean implements FactoryBean{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public Object getObject() throws Exception { return new Car(name, "beijing");//调用构造函数 } @Override public Class getObjectType() { return Car.class; } @Override public boolean isSingleton() { return true; }} |
|
1
2
3
|
<bean id="car" class="com.test.spring04.CarFactoryBean"> <property name="name" value="BMW"></property></bean> |
|
1
2
|
Car car = (Car) applicationContext.getBean("car");System.out.println(car); |
在IOC容器中通过注解配置Bean
组件扫描(component scanning):Spring可以从classpath下自动扫描、侦测和实例化具有特定注解的组件。
特定组件包括:
-@Component 基本注解,标识了一个受Spring管理的组件
-@Repository 标识持久层组件
-@Service 标识服务层(业务层)组件
-@Controller 标识表现层组件
对于扫描到的组件,Spring有默认的莫名策略:使用非限定类名,第一个字母小写,也可以在注解中通过value属性值标识组件的名称。

浙公网安备 33010602011771号