前言:
    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. UVA 11404 简单LCS模型DP 字典序比较

    这个题目求某个字符串中含的最长的回文子串. 就是一个很简单的LCS模型吗,而且我不明白为什么网上这么多人都说仿照某写法把字符串先逆序一下,然后求LCS,我只想问一下,有必要吗? 直接按LCS的套路来就 ...

  2. Centos7下yum安装软件报错解决办法

    Traceback (most recent call last): File "/usr/bin/yum", line 29, in yummain.user_main(sys. ...

  3. 对PHP-GC(垃圾回收)的一点理解

    一直对php的垃圾回收机制不明不白故自己开贴记录下. 首先,说到垃圾回收,得先知道什么情况下才能产生垃圾. 如果一个变量refcount在增加,说明在被使用,不是垃圾. 如果一个变量的refcount ...

  4. postfix简单记录

    1.将/etc/postfix/main.cf编辑 myhostname和mydomain等 2.即可测试发送邮件 3.安装DNS功能,其中13和21行改成any yum install bind b ...

  5. CSS——fixed 固定定位相对于父容器

    position:fixed 固定定位 用 left top 都是相对于浏览器的. 我今天想给网页做一个固定定位的导航 偶然间发现.可以用margin 相对于父容器定位. 小伙伴们可以试试. 不用le ...

  6. IO流的学习以及统计次数最多的单词

    IO流: 处理数据类型:字节流(InputStream  OutputStream)和字节流(Reader  Writer) 数据流向不同:输入流和输出流(FileInputStream   File ...

  7. 创建DateFrame的常用四种方式

    import pandas as pd %pylab 一.使用numpy创建 df = pd.DataFrame(np.arange(16).reshape((4,4)), index=list('a ...

  8. JavaScript 闭包究竟是什么JavaScript 闭包究竟是什么

    用JavaScript一年多了,闭包总是让人二丈和尚摸不着头脑.陆陆续续接触了一些闭包的知识,也犯过几次因为不理解闭包导致的错误,一年多了资料也看了一些,但还是不是非常明白,最近偶然看了一下 jQue ...

  9. JAVA多线程之状态转换图

    线程状态转换图如下: 1.新建(new):线程对象被创建后就进入了新建状态.如:Thread thread = new Thread(); 2.就绪状态(Runnable):也被称为“可执行状态”.线 ...

  10. \_\_setitem\_\_和\_\_getitem和\_\_delitem__

    目录 __setitem__和__getitem和__delitem__ 一.__setitem__ 二.__getitem__ 三.__delitem__与__delattr__ 四.总结 __se ...