解读Spring定义Bean的两种方式:<bean>和@Bean

作者:恐龙弟旺仔 时间:2023-01-25 23:37:51 

前言    

Spring中最重要的概念IOC和AOP,实际围绕的就是Bean的生成与使用。

什么叫做Bean呢?我们可以理解成对象,每一个你想交给Spring去托管的对象都可以称之为Bean。

今天通过Spring官方文档来了解下,如何生成bean,如何使用呢?

1.通过XML的方式来生成一个bean

最简单也是最原始的一种方式,通过XML来定义一个bean,我们来看下其过程

1)创建entity,命名为Student

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable {
 
    private static final long serialVersionUID = -2088281526481179972L;
    private int id;
    private String name;
    private int age;
}    

2)在beans.xml中定义Student

    <!-- 1.空值的student -->
    <bean id="studentNoValue" class="domain.Student"/>
 
    <!-- 2.带值的student -->
    <bean id="student" class="domain.Student">
        <property name="id" value="11"/>
        <property name="age" value="22"/>
        <property name="name" value="jack"/>
    </bean>
 
    <!-- 3.全参构造:使用成员变量名称对应 -->
    <bean id="studentConstruct" class="domain.Student">
        <constructor-arg name="age" value="22"></constructor-arg>
        <constructor-arg name="id" value="11"></constructor-arg>
        <constructor-arg name="name" value="jack"></constructor-arg>
    </bean>
 
    <!-- 4.全参构造:使用成员变量index对应 -->
    <bean id="studentConstruct2" class="domain.Student">
        <constructor-arg index="0" value="11"></constructor-arg>
        <constructor-arg index="1" value="jack"></constructor-arg>
        <constructor-arg index="2" value="22"></constructor-arg>
    </bean>
 
    <!-- 5.全参构造:使用成员变量类型对应 -->
    <bean id="studentConstruct3" class="domain.Student">
        <constructor-arg type="int" value="11"></constructor-arg>
        <constructor-arg type="java.lang.String" value="jack"></constructor-arg>
        <constructor-arg type="int" value="22"></constructor-arg>
    </bean>

总结:可以看到,创建bean的方式多种多样,我们可以通过属性来赋值<property>,也可以通过构造参数来赋值<constructor>,关于构造赋值以上展示了三种方式,我们可以根据自己的需求来选择对应的方式。

3)测试bean

public class ApplicationContextTest {
 
    @Test
    public void testXml(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        Student studentNoValue = (Student) applicationContext.getBean("studentNoValue");
        Student studentFullValue = (Student) applicationContext.getBean("studentFullValue");
        System.out.println(studentNoValue);
        System.out.println(studentFullValue);
 
 
        Student studentConstruct1 = (Student) applicationContext.getBean("studentConstruct");
        Student studentConstruct2 = (Student) applicationContext.getBean("studentConstruct2");
        Student studentConstruct3 = (Student) applicationContext.getBean("studentConstruct3");
        System.out.println(studentConstruct1);
        System.out.println(studentConstruct2);
        System.out.println(studentConstruct3);
 
        Book bookChinese = (Book) applicationContext.getBean("bookChinese");
        System.out.println(bookChinese);
    }
}
// res:
Student(id=0, name=null, age=0)
Student(id=11, name=jack, age=22)
Student(id=11, name=jack, age=22)
Student(id=11, name=jack, age=22)
Student(id=11, name=jack, age=22)

2.<bean>标签深入了解

我们刚才介绍了最基本的Bean使用方式,大家会发现<bean>标签还有其他的属性,比如name/scope/lazy-init/init-method/...等,这些是做什么用的呢?我们在实际的工作中怎么使用呢?

1)name属性

在介绍name属性之前,我们先来看下ApplicationContext.getBean()的两种方式

* ApplicationContext.getBean(String name)

* ApplicationContext.getBean(Class<T> requiredType)

第一种方式的这个name是什么呢?我们应该如何定义,又该如何使用呢?

// 上文示例中,我们只是指定了Bean的id和class,如下所示
<bean id="studentNoValue" class="domain.Student" />
    
// 具体获取bean的方式如下:
Student studentNoValue = (Student) applicationContext.getBean("studentNoValue");
 
// 可以看到,在没有指定bean的name属性的时候,默认使用id来获取bean,当做name使用
// 如果我们不想根据id获取,那就需要主动指定bean的name属性,如下所示:
<bean id="studentNoValue" class="domain.Student" name="stuName"/>
// 这样在获取的时候,就需要使用指定的名称来获取,再根据id来获取的时候就会报错了
Student studentNoValue = (Student) applicationContext.getBean("stuName");
    * 根据Class来获取这种方式很好理解,这个不关心你定义的id或者name是什么,使用如下:

Student studentNoValue = (Student) applicationContext.getBean(Student.class);

2)scope属性

可以看到,在使用scope属性的时候,提示有两种输入值,分别是singleton/prototype

这个就代表了Spring-Bean的两种创建模式,单例模式和原型模式

* Spring默认使用单例模式来创建Bean,通过ApplicationContext所获得的bean都是同一个bean(在beanName相同的情况下),我们可以来验证下

Student studentNoValue = (Student) applicationContext.getBean("stuName");
Student studentNoValue2 = (Student) applicationContext.getBean("stuName");
 
System.out.println(studentNoValue == studentNoValue2);// true

可以看到的是结果输入为true,从工厂类中两次获取的stuName是同一个对象。

* 下面来验证下原型模式

原型模式:每次获取的bean都为一个新的对象

// 修改beans.xml中studentNoValue的scope为prototype
<bean id="studentNoValue" class="domain.Student" name="stuName" scope="prototype"/>
 
// 然后执行上面的测试代码
Student studentNoValue = (Student) applicationContext.getBean("stuName");
Student studentNoValue2 = (Student) applicationContext.getBean("stuName");
 
System.out.println(studentNoValue == studentNoValue2);// false

可以看到,输出结果为false,原型模式下从工厂类两次获取的stuName不是同一个对象。

3)init-method和destroy-method方法

见名知意,init-method应该是初始化方法的意思,destroy-method应该是销毁方法的意思。那怎么使用呢?

// 在Student.java中添加init()方法和destroy()方法
public void init(){
    System.out.println("student init...");
}
 
public void destroy(){
    System.out.println("student destroy...");
}
 
// 在beans.xml中studentNoValue的bean上添加 init-method和destroy-method
<bean id="studentNoValue" class="domain.Student" name="stuName" init-method="init" destroy-method="destroy"/>
 
// 测试方法如下:
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Student studentNoValue = (Student) applicationContext.getBean("stuName");
 
applicationContext.close();
 
// 执行结果:
student init...
student destroy...    

总结:在获取bean的时候init()方法被执行,在容器被销毁的时候,执行了destroy()方法

根据这个,我们可以在初始化bean和销毁bean的时候做点什么,比如关闭连接,保存记录之类的操作。

延伸:那么初始化init()方法在构造方法之前调用,还是之后调用呢?读者可以自行验证下

总结:还有一些其他属性,笔者就不再一一验证了,下面说一下通过JavaConfig的方法来实现bean的定义。

3.JavaConfig方式的bean定义

JavaConfig是Spring4.x推荐的配置方式,可以完全替代XML的方式定义。

1)如何定义一个Bean

// 创建一个类,命名为SpringConfiguration
@Configuration
public class SpringConfiguration {
    @Bean
    public Student student(){
        return new Student(11,"jack",22);
    }
}
 
// 使用bean
AnnotationConfigApplicationContext applicationContext
                = new AnnotationConfigApplicationContext(SpringConfiguration.class);
Student student = (Student) applicationContext.getBean("student")
System.out.println(student);
 
// res:
Student(id=11, name=jack, age=22)

相对于XML的使用方式而言,JavaConfig的使用方式基本是同步的

* @Configuration等同于<beans></beans>

* @Bean等同于<bean></bean>

* 通过AnnotationConfigApplicationContext来加载JavaConfig

* 方法名student()就等同于<bean>中的id,默认方法名就是beanName

2)@Bean的其他参数

* name属性等同于<bean>的name

* initMethod属性等同于<bean>的init-method

* destroyMethod属性等同于<bean>的destroy-method

* scope这个比较奇怪,不属于@Bean的参数,这是一个单独的注解,使用方式如下

@Bean(name = "stu",autowire = Autowire.BY_TYPE)
@Scope(value = "singleton")
public Student student(){
    return new Student(11,"jack",22);
}

来源:https://kldwzz.blog.csdn.net/article/details/89761303

标签:Spring,Bean,,@Bean
0
投稿

猜你喜欢

  • WCF和Remoting之间的消息传输

    2023-04-15 01:01:20
  • C#资源释放方法实例分析

    2022-03-22 04:46:20
  • Java的StringBuilder在高性能场景下的正确用法

    2021-11-23 17:57:01
  • Servlet 过滤器详细介绍

    2021-10-21 13:51:57
  • java中Swing会奔跑的线程侠

    2021-12-14 23:47:36
  • C#中Dynamic和Dictionary性能比较

    2022-05-11 12:16:33
  • Spring框架初始化解析

    2021-06-09 16:46:59
  • Android中Market的Loading效果实现方法

    2023-11-16 09:37:33
  • 深入了解Java核心类库--Math类

    2023-08-19 01:06:21
  • Android实现九格智能拼图算法

    2021-11-07 22:40:11
  • android自定义Camera实现录像和拍照

    2022-02-26 19:00:02
  • Java实现查找算法的示例代码(二分查找、插值查找、斐波那契查找)

    2022-05-28 04:17:38
  • Android实现通讯录效果——获取手机号码和姓名

    2021-10-25 11:53:59
  • C#图表算法之无向图

    2021-08-08 22:50:20
  • 区分Java中的ArrayList和LinkedList

    2021-05-26 11:09:55
  • Java模拟多线程实现抢票代码实例

    2022-11-17 07:41:51
  • 每日六道java新手入门面试题,通往自由的道路

    2023-11-13 16:22:29
  • Android SearchView搜索控件使用方法详解

    2022-07-09 16:49:21
  • C#中关于zip压缩解压帮助类的封装 附源码下载

    2021-08-19 00:37:22
  • Java字节与字符流永久存储json数据

    2022-12-27 21:10:13
  • asp之家 软件编程 m.aspxhome.com