Spring 学习(一)——装配Bean

文章目录

    • XML 方式装配Bean
      • 一、实例化 javaBean
      • 二、属性注入
      • 三、使用Spring 表达式语言进行装配(SpEL)
    • 注解装配Bean
      • 一、装配Bean
      • 二、注入属性
    • 整合多个Spring 文件
    • 自动装配

前言
Spring 是一个基于容器的框架,但是如果没有配置那它就是一个空容器,所以我们需要配置Spring 来告诉Spring 加载哪些Bean以及如何装配这些Bean。
我们主要来讲在XML文件里怎么装配Bean。

XML 方式装配Bean

一、实例化 javaBean

首先我们需要创建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 支持三种属性注入

  • 构造器注入
  • setter 方法注入
  • 接口注入

Spring 框架支持的属性注入

  • 构造器注入
  • setter 方法注入
    1.一般属性注入
    1.构造器注入
    先给Student 类加一个属性name 吧。既然是构造器注入,那得加一个带参的构造函数吧。
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
    

元素构建了一个Properties 值,这个Properties 的每一个成员都由元素定义,每一个元素都由一个key 属性,其定义了Properties 每个成员的键,而每一个成员由元素的内容所定义。
**装配内部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:作为元素所有属性的前缀来装配属性


    

三、使用Spring 表达式语言进行装配(SpEL)

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]}

上面说的这些运算符都可以混合使用

注解装配Bean

一、装配Bean

讲完了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(value = “user”)
    这个注解对类女性标注,它可以被Spring 容器识别,Spring 容器将自动将类转化成容器管理的Bean。

除了@Component,Spring 还提供了三个与其等效的注解。一般用于Web 项目,对DAO,service,web层进行注解。

  • @Repository:对DAO实现类进行注解

  • @Service:对service实现类进行注解

  • @Controller:对web层Controller实现类进行注解

之所以用着几个注解,是为了让注解类的用途清晰化。下面这个是设置Bean 的生命周期范围。

  • @Scope(value = “singleton”):Bean 的作用域,和XML 中Scope 属性作用一样

下面这两个注解修饰方法,相当于bean的init-method和destory-method属性的功能。

  • @PostConstruct:在类被创建时调用
  • @PreDestroy:类被销毁是时调用

二、注入属性

1.注入一般的属性

  • @Value:为Bean 进行属性注入
    上面那个类里面有一个id的属性,用这个注解来为其注入一个值
@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 还提供了其它两个注解,三个注解的区别如下:

  • @Autowired
    @Autowired默认按类型匹配的方式,在容器中查找匹配的Bean,当有且只有一个匹配的Bean时,Spring将其注入到@Autowired注解的变量中。但是如果容器中有超过一个以上的匹配Bean时,例如有两个UserService类型的Bean,这时就不知道将哪个Bean注入到变量中,就会出现异常
  • @Qualifier(“userservice”)
    这个注解按照指定的名字注入属性
  • @Resource(name=“userservice”)
    结合和前两个注解,当容器中只有一个匹配的Bean 时,直接注入,当容器中有多个匹配的Bean时,按照指定的名字匹配

整合多个Spring 文件

对于一个大型项目而言,可能有多个XML配置文件,在启动Spring容器时,可以通过一个String数组指定这些配置文件。Spring还允许我们通过< import >标签将多个配置文件引入到一个文件中,进行配置文件的集成,这样启动Spring容器时,就仅需指定这个合并好的配置文件即可。

1.使用Spring 数组整合所有文件

ApplicationContext ac=new ClassPathXmlApplicationContext(new String[]{"bean1.xml","bean2.xml"});

2.使用import 标签

 //resource属性指定配置文件位置,支持Spring标准的资源路径
 
 

自动装配

Spring 提供了四种自动装配的策略

  • byName
    把与Bean 的属性具有相同名字的其它Bean 自动装配到Bean 对应的属性中
  • byType
    把与Bean 的属性具有相同类型的Bean 自动装配到Bean 的属性中。但是如果当前应用上下文中有多个与Bean 属性具有相同类型的其它Bean,Spring 会抛出异常。
    那么当有多个Bean 都满组条件的时候,我们可以为其首选一个Bean,可以使用 元素的primary属性,将这个属性设置为true即可,但是primary 属性默认被设置为true,所以等于所有的Bean 都是首选Bean,所以也就不存在首选了,所以我们不得不讲其它的都设置为false。
    如果我们在自动装配时想忽略某个Bean,可以设置这些Bean 的autowire-candidate属性为false。这等于是取消了其作为候选Bean 的资格。
  • constructor
    把与Bean 的构造器入参具有相同类型的Bean 自动装配到构造器对应的入参中,值得注意的是,它还是用类型进行匹配,所以依然会碰到上面的问题,而且,当Bean 有多个构造器,Spring 不会帮我们判断使用哪个构造器,它会直接抛出异常。
  • autodetect
    它会首先使用constructor 进行动装配,如果失败再尝试用byType。

使用
只需要在Bean 标签里面加上autowire就可以啦

 

默认的自动装配 default-autowire
默认情况下这个属性为false,表示所有的属性都不使用自动郑培,除非在bena 上设置了autowire。
当我们想让配置文件中所有的Bean 都进行自动装配的时候,在beans 上增加属性default-autowire


注意
使用了默认的装配策略,我们依然可以使用元素的autowire 属性来覆盖默认的装配策略。
而且,我们使用了自动装配策略,并不代表我们不能对该Bean的某些属性进行显式装配。

你可能感兴趣的:(Spring)