首先我们需要创建Spring 配置。
在XML文件中声明Bean时,Spring配置文件的根元素来源于Spring beans 命名空间所定义的元素,下面是一个典型的Spring XML配置文件
1.bean 实例化的三种方式
1.通过无参构造器创建
这是一个javaBean 类
public class Student{
public void show(){
System.out.println("Student show……");
}
}
在XML文件里面进行声明
测试一下
//使用一般工厂获取对象
public static void test2() {
ApplicationContext context = new ClassPathXmlApplicationContext("springbean.xml");
Student student = (Student) context.getBean("student");
student.show();
}
2.通过静态工厂
这是一个静态工厂
public class StaticFactory {
public static Student getBean(){
return new Student();
}
}
在XML里面配置
class :表示我们想要的对应的类。
factory-method:表示我们要调用的类里面包含的方法
测试方法
//使用静态工厂获取对象
public static void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("springbean.xml");
Student student = (Student) context.getBean("student2");
student.show();
}
3.使用一般工厂创建对象
一般工厂类
public class Factory {
//通过普通工厂类创建student类
public Student getBean(){
return new Student();
}
}
配置类
测试
//使用一般工厂获取对象
public static void test2() {
ApplicationContext context = new ClassPathXmlApplicationContext("springbean.xml");
Student student = (Student) context.getBean("student3");
student.show();
}
注意:在这些Bean 中必须要有无参构造器,这些类是通过反射得到的,必须要有无参构造器。
2.Bean 的作用域
所有的Spring Bean 默认都是单例的。当容器分配一个Bean时,它总是返回的是同一个实例。那有时候我们需要获得唯一的Bean ,那么我们可以在配置Bean 时为其声明一个作用域
scope 属性表示了这个Bean 的作用域
作用域 | 定义 |
---|---|
singleton | 在每一个Spring容器中,一个Bean定义只有一个对象实例 |
prortotype | 允许Bean 的定义可以被实例化任意次(每次调用都创建一个实例) |
request | 在一次HTTP请求中,每个Bean 定义对应一个实例。该作用域仅在基于Web的Spring 上下文(例如Spring MVC)中才生效 |
session | 在一次HTTP Session请求中,每个Bean 定义对应一个实例。该作用域仅在基于Web的Spring 上下文(例如Spring MVC)中才生效 |
global-session | 在一个全局HTTP Sesion中,每个Bean定义对应一个实例。该作用域仅在Portlet上下文中才有效 |
3.Bean 的初始化和销毁
当实例化一个Bean 时,可能需要一些初始化的操作确保该Bean 处于可用状态。同样,当不再需要Bean,将其从容器中移除,可能也需要一些清除工作。Spring 提供了Bean生命周期的各种方法。初始化和销毁只需要用init-method 和destory-method 参数来配置元素。
给Student 类添加这么两个方法
public void start(){
System.out.println("开始");
}
public void end(){
System.out.println("结束");
}
修改配置文件
因为我们没有进行销毁,所以并没有调用end()方法,但是在对象刚被实例化的时候它就调用了start()方法,这足以说明问题。
InitializingBean 和DisposableBean
为Bean 定义初始化和销毁方法的另一种可选的方式是让Bean 实现Spring 的这两个接口。Spring 容器以特殊的方式对待实现这两个接口的Bean,允许它们进入Bean的生命周期。InitializingBean 声明了一个afterPropertiesSet()方法作为初始化方法。而DisPosableBean 声明了一个destory()方法,该方法在Bean 从应用文上下移除时会被调用。
优点:Spring 能够自动检测实现了这些接口的Bean,而无需额外的配置。
缺点:Bean 与Spring 的API产生了耦合。唯一可以使用Spring 生命周期接口的场景是开发一个明确在Spring 容器内使用的框架Bean。
默认的init-method 和destory-method
如果在上下文中定义的很多Bean都拥有相同名字的初始化和销毁方法,可以使用 元素的default-init-method 和defaul-destory-method属性。
default-init-method 属性为应用上下文中所有的bean 设置了共同的初始化方法。
defaul-destory-method 属性为应用上下文中所有的bean 设置了共同的销毁方法。
上面这个类没有任何属性,那么我们怎么样注入属性给javaBean呢?
java 支持三种属性注入
Spring 框架支持的属性注入
public class Student {
private String name;
public Student() {
}
public Student(String name) {
System.out.println("构造器");
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("set 方法注入属性");
this.name = name;
}
}
配置文件
测试
public static void iocTest(){
//加载spring配置文件,创建spring对象
ApplicationContext context = new ClassPathXmlApplicationContext("springbean.xml");
Student student = (Student) context.getBean("student");
}
2.setter 方法注入
重新测试一下,控制台应该会打印“set 方法注入属性”
2.复杂对象的注入
对象
这里有两个类,UserService 和UserDao
public class UserService {
UserDao userDao1;
public UserDao getUserDao1() {
return userDao1;
}
public void setUserDao1(UserDao userDao1) {
this.userDao1 = userDao1;
}
public void add(){
userDao1.add();
}
}
public class UserDao {
public void add(){
System.out.println("图论");
}
}
在XML里面装配它
ref 表示是一个引用。
我们给Student 里面增加这么几个属性
private String[] str;
private List list;
private Map map;
private Properties sp;
数组
1
2
标签表示数组,在这个标签下有value 属性,我们可以定义任意多个 value 给数组
集合(List,Set)
你
好
list 集合和数组是一样的,当是Set集合的时候,可以把标签改为
Map 集合
Map 集合和另外两个集合优点不一样,标签表示这是一个map,map 存储的是键值对,则代表一个节点,节点包括key 和value。
entry 中的元素不仅仅有这两个,看一下这个表
属性 | 用途 |
---|---|
key | 指定map 中entry 的键为String |
key-ref | 指定map中entry 的键为Spring 上下文中其他的Bean 引用 |
value | 指定map中entry的值为String |
value-ref | 指定map中entry 的值为Spring上下文中其它的Bean 引用 |
Properties 集合
如果配置的map 和值都为String,我们可以考虑使用Properties代替map。Properties 提供了和map大致相同的功能,但是它指定键和值都必须为String
wjm
**装配内部Bean **
或许你可能很熟悉内部类的概念了,类似的,内部Bean 是定义在其他Bean 内部的Bean。
用那个UserService和UserDao 的例子
内部Bean 不仅使用与setter 注入,还适用于构造器注入
内部Bean 没有id,我们也不可能通过名字来引用内部的Bean。所以内部Bean 也不能被复用,仅仅适用于一次性注入。
装配空值
在有些场景下,如果不能完全确定属性的值为null,那么就必须显式的为该属性装配一个null值。
3.使用Spring 的命名空间p来装配属性
命名空间p的schema URI为xmlns:p=“http://www.springframework.org/schema/p”,只需要在Spring 的XML配置中增加一下声明就可以用了
可以使用p:作为
SpEL是在Spring3时提出的,在这个过程中所使用的表达式会在运行时计算得到值,然后以一种强大和简洁的方式将值装配到Bean属性和构造器参数中去。
怎样使用SpEL表达式
SpE表达式要放到#{ }中,在括号里面就是表达式了。
表示字面值
#{1}
这就是一个简单的表达式,表示为1,这个表达式没有任何意义,直接用1也可以的,这只是为了让大家了解什么是表达式。不仅如此,它还可以用来表示浮点数、String以及Boolean,甚至数值还可以用科学计数法的方式进行表示。
#{1.36} //表示浮点
#{'hello'} //表示String
#{false} //表示Boolean
#{9.87E4} //科学计数法
引用Bean 、属性和方法
假设我们现在有一个ID 为 student 的bean,可以通过 #{student} 把这个Bean 装配给其它Bean
#{student}//调用bean
#{student.name}//调用属性
#{student.show()}//调用方法
在表达式中使用类型
如果要在SpEL表达式中使用类作用域的方法和常量就使用T{}
#{T(java.lang.Math).PI}//访问Math类的常量
#{T(java.lang.Math).random()}//访问Math类的静态方法
SpEL 运算符
算数运算 | + 、-、 *、 / 、%、^ |
比较运算 | <、>、==、<=、>=、 lt、gt、eq、le、ge |
逻辑运算 | and、 or、 not |
条件运算 | ?:(ternary)、?:(Elvis) |
正则表达式 | matches |
算数运算符和在java 里的作用一样
比较运算符也没变,结果是个Boolean 值。
计算集合
SpEL最神奇的地方就是与集合和数组相关的。[] 中括号运算符用来从数组或者集合中获取元素,不仅如此,它还可以从String 中获取一个字符
#{student.list[1]} //表示从student 这个bean 的list 属性拿到第2个元素,下标从0开始
#{student.name[2]} //从student 的name属性拿到了字符串中的第三个字符
SpEL表达式还提供了查询运算符(.?[])用来对集合进行过滤
假设我们有一个Student 的集合students,Student 有一个class 的属性
//我们得到了students 中subject 属性为math的所有的class
#{students.class.?[subject eq "math"]}
(.^[])和(.$[])运算符分别表示在集合中查询的第一个匹配项和最后一个匹配项
//在列表里查第一个subject 为math的 calss
#{students.class.^[subject eq "math"]}
//在列表里查最后一个subject 为math的 calss
#{students.class.$[subject eq "math"]}
SpEL 还提供了投影运算符( .![] ),它会从集合的每个成员中选择特定的属性放到另外一个集合中。
//将subject 属性映射到一个新的String 集合中去
#{students.class.![subject]}
上面说的这些运算符都可以混合使用
讲完了XML装配Bean,我们通过一个例子简单看一下注解方式怎么装配Bean。
XML 配置
使用注解之前,我们要先导入4+2+aop的jar包,同时引入约束 beans+context
在配置文件加上开启注解扫描的标签
加上这句话,Spring会自动的去我们指定的包里扫面类以及方法,看其是否有注解。
@Component(value = "user")
//等同于
@Scope(value = "singleton")
public class User {
private int id;
@PostConstruct
public void add(){
System.out.println("add……");
}
}
除了@Component,Spring 还提供了三个与其等效的注解。一般用于Web 项目,对DAO,service,web层进行注解。
@Repository:对DAO实现类进行注解
@Service:对service实现类进行注解
@Controller:对web层Controller实现类进行注解
之所以用着几个注解,是为了让注解类的用途清晰化。下面这个是设置Bean 的生命周期范围。
下面这两个注解修饰方法,相当于bean的init-method和destory-method属性的功能。
1.注入一般的属性
@Value(value = "1")
private int id;
通过Setter 也可以注入
@Value(value = "1")
public void setId(int id) {
this.id = id;
}
2.注入引用类型属性
@Autowired
UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
除了@Autowired ,Spring 还提供了其它两个注解,三个注解的区别如下:
对于一个大型项目而言,可能有多个XML配置文件,在启动Spring容器时,可以通过一个String数组指定这些配置文件。Spring还允许我们通过< import >标签将多个配置文件引入到一个文件中,进行配置文件的集成,这样启动Spring容器时,就仅需指定这个合并好的配置文件即可。
1.使用Spring 数组整合所有文件
ApplicationContext ac=new ClassPathXmlApplicationContext(new String[]{"bean1.xml","bean2.xml"});
2.使用import 标签
//resource属性指定配置文件位置,支持Spring标准的资源路径
Spring 提供了四种自动装配的策略
使用
只需要在Bean 标签里面加上autowire就可以啦
默认的自动装配 default-autowire
默认情况下这个属性为false,表示所有的属性都不使用自动郑培,除非在bena 上设置了autowire。
当我们想让配置文件中所有的Bean 都进行自动装配的时候,在beans 上增加属性default-autowire
注意
使用了默认的装配策略,我们依然可以使用
而且,我们使用了自动装配策略,并不代表我们不能对该Bean的某些属性进行显式装配。