前言:
    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);
}
总结:

以上全文,我们通过两种方式来定义一个Bean,默认推荐JavaConfig。

Spring定义Bean的两种方式:和@Bean的更多相关文章

  1. spring 注入bean的两种方式

    我们都知道,使用spring框架时,不用再使用new来实例化对象了,直接可以通过spring容器来注入即可. 而注入bean有两种方式: 一种是通过XML来配置的,分别有属性注入.构造函数注入和工厂方 ...

  2. Spring创建JobDetail的两种方式

    一.Spring创建JobDetail的两种方式 二.整合方式一示例步骤 1.将spring核心jar包.quartz.jar和Spring-context-support.jar导入类路径. 2.编 ...

  3. spring配置属性的两种方式

    spring配置属性有两种方式,第一种方式通过context命名空间中的property-placeholder标签 <context:property-placeholder location ...

  4. Spring整合Struts的两种方式介绍

    1 使用Spring托管Struts Action 该种方式就是将Struts Action也视为一种Bean交给Spring来进行托管,使用时Struts的配置文件中配置的Action的classs ...

  5. spring实现定时任务的两种方式

    本文为博主原创,未经允许不得转载 项目中要经常事项定时功能,在网上学习了下用spring的定时功能,基本有两种方式,在这里进行简单的总结, 以供后续参考,此篇只做简单的应用. 1.在spring-se ...

  6. Spring整合Hibernate的两种方式

    在使用spring注解整合hibernate时出现"org.hibernate.MappingException: Unknown entity: com.ssh.entry.Product ...

  7. 使用react定义组件的两种方式

    react组件的两种方式:函数定义,类定义 在定义一个组件之前,首先要明白一点:react元素(jsx)是react组件的最基本的组成单位 组件要求: 1,为了和react元素进行区分,组件名字首必须 ...

  8. Spring实例化Bean的三种方式及Bean的类型

    1.使用类构造器实例化  [默认的类构造器] <bean id=“orderService" class="cn.itcast.OrderServiceBean"/ ...

  9. React 中的 定义组件的 两种方式

    React 中创建 Components 的方式有两种:Function and Class 定义一个组件最简单的方法就是写一个 JavaScript 函数 function Welcome(prop ...

随机推荐

  1. 使用labelImg制作自己的数据集(VOC2007格式)用于Faster-RCNN训练

    https://blog.csdn.net/u011956147/article/details/53239325 https://blog.csdn.net/u011574296/article/d ...

  2. shell中获取文件目录方法

    1.``:表示执行对应的命令,嵌套时使用`\`\``,注意\进行转义,同时执行多个命令时使用:隔开file=`cd "\`dirname $0\`";pwd`echo $file ...

  3. Codeforces Round #571 (Unrated for Div. 1+Div. 2)

    A 略 B 被删了,被这个假题搞自闭了,显然没做出来. C 开始莽了个NTT,后来发现会TLE,其实是个SB前缀和,对于这题,我无**说. #include<bits/stdc++.h> ...

  4. java类的实例化顺序

    1. 父类静态成员和静态初始化块 ,按在代码中出现的顺序依次执行 2. 子类静态成员和静态初始化块 ,按在代码中出现的顺序依次执行 3. 父类实例成员和实例初始化块 ,按在代码中出现的顺序依次执行 4 ...

  5. Python笔记_第四篇_高阶编程_进程、线程、协程_4.协程

    1.协程的概念: 子程序或者子函数,在所有语言中都是层级调用,比如A调用B,再B执行的过程中又可以调用C,C执行完毕返回,B执行返回,最后是A执行完毕返回.是通过栈来实现的,一个线程就是执行一个自称, ...

  6. UML-类图-箭头

    概览 1.泛化 一般理解为 继承.实线+空心箭头 2.依赖 成员变量.局部变量.参数.虚线+箭头 public class Sale { public void updatePriceFor(Prod ...

  7. GitHub 中 readme 如何添加图片

    一.Readme 是什么 readme文件一般是放在github 每个repo的根目录下,用来解释.说明本repo的主要内容和相关信息.而且在repo主页进去的时候会被自动加载.一般采用md标记的文本 ...

  8. ccf-csp 任务调度,回溯算法我觉得ok神**wa了

    #include<iostream> #include<string.h> #include<cmath> #define M 41 #define min(a,b ...

  9. js等于符号的详解

    JavaScript == 与 === 区别 1.对于 string.number 等基础类型,== 和 === 是有区别的 a)不同类型间比较,== 之比较 "转化成同一类型后的值&quo ...

  10. 给Office文档添加水印效果【测试有效】

    private void button1_Click(object sender, EventArgs e) { string test1 = "C:\\test.docx";// ...