博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring IOC 详解
阅读量:4949 次
发布时间:2019-06-11

本文共 13776 字,大约阅读时间需要 45 分钟。

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=root
password=
123456
driverClass=com.mysql.jdbc.Driver
jdbcUrl=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属性值标识组件的名称。

转载于:https://www.cnblogs.com/yudar/p/4603127.html

你可能感兴趣的文章
jQuery中的事件与动画
查看>>
页面加载骨架
查看>>
关于android系统不关屏设置
查看>>
SONY VPCS138EC降级安装XP
查看>>
[luogu4201][bzoj1063]设计路线【树形DP】
查看>>
手机抓包-手机劫持域名到指定服务器
查看>>
被放逐的皇后 金建云
查看>>
Javascript 有用参考函数
查看>>
点群的判别(三)
查看>>
GNSS 使用DFT算法 能量损耗仿真
查看>>
网页抓取 总结
查看>>
【转】Simulink模型架构指导
查看>>
MYSQL数据库的导出的几种方法
查看>>
SQL Server-5种常见的约束
查看>>
硬件之美
查看>>
[转载]java开发中的23种设计模式
查看>>
表格的拖拽功能
查看>>
函数的形参和实参
查看>>
文字过长 用 ... 表示 CSS实现单行、多行文本溢出显示省略号
查看>>
1Caesar加密
查看>>