Spring系列二:基于注解配置bean【建议收藏】

这篇具有很好参考价值的文章主要介绍了Spring系列二:基于注解配置bean【建议收藏】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

上文中, 我们学习到了 Spring系列一:spring的安装与使用

接下来我们学习, 通过XML配置bean
Spring系列二:基于注解配置bean【建议收藏】,Spring5,spring,python,hive


Bean管理包括两方面: 创建bean对象, 给bean注入属性

💖通过类型获取bean

案例: 通过spring的ioc容器, 获取一个bean对象, 获取方式: 按类型.

<!--配置Monster, 通过类型获取-->
<bean class="com.zzw.spring.bean.Monster">
    <!--
    解读
    1.当我们给某个bean对象设置属性的时候
    2.底层是使用对应的setter方法完成的, 比如setName()
    3.如果没有这个方法, 就会报错
    -->
    <property name="monsterId" value="100"/>
    <property name="name" value="孙悟空"/>
    <property name="skill" value="火眼金睛"/>
</bean>

演示通过bean的类型获取对象

@Test
public void getBeanByType() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    //直接传入class对象/类型
    Monster bean = ioc.getBean(Monster.class);
    System.out.println("bean=" + bean);
}

细节
按照类型获取bean, 要求ioc容器中的同一个类的bean只能有一个, 否则会抛出异常 NoUniqueBeanDefinationException

这种方式的应用场景: 比如XxxAction / Servlet / Controller, 或XxxService在一个线程中只需要一个对象实例(单例)的情况

在容器配置文件(比如beans.xml)中给属性赋值. 底层是通过setter方法完成的. 所以需要提供setter方法.

💖通过指定构造器配置bean

<!--配置Monster对象, 并且指定构造器-->
<!--
解读
1.constructor-arg标签可以指定使用构造器的参数
2.index表示构造器的第几个参数, 从0开始计算的
3.除了可以通过index, 还可以通过name / type来指定参数方式
4.解除大家的疑惑: 类的构造器, 不能有完全相同类型和顺序的构造器, 所以可以通过type来指定
 一个类中的两个构造器, 参数的类型和顺序不能完全相同
 可以类型相同, 但顺序不同 [方法重载]
-->
<bean class="com.zzw.spring.bean.Monster" id="monster03">
   <constructor-arg value="100" index="0"/>
   <constructor-arg value="齐天大圣" index="1"/>
   <constructor-arg value="如意金箍棒" index="2"/>
</bean>

<bean class="com.zzw.spring.bean.Monster" id="monster04">
   <constructor-arg value="200" name="monsterId"/>
   <constructor-arg value="斗战胜佛" name="name"/>
   <constructor-arg value="无法无天" name="skill"/>
</bean>

<bean class="com.zzw.spring.bean.Monster" name="monster05">
   <constructor-arg value="300" type="java.lang.Integer"/>
   <constructor-arg value="猪悟能" type="java.lang.String"/>
   <constructor-arg value="追嫦娥~" type="java.lang.String"/>
</bean>

演示通过构造器来设置属性

@Test
public void setBeanByConstructor() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");

    Monster monster03 = ioc.getBean("monster03", Monster.class);
    System.out.println("monster03=" + monster03);
}

Spring系列二:基于注解配置bean【建议收藏】,Spring5,spring,python,hive
Spring系列二:基于注解配置bean【建议收藏】,Spring5,spring,python,hive
通过index属性来区分是第几个参数;
通过type属性来区分是什么类型(按照顺序, 这是可以的)

💖通过p名称空间配置bean

xmlns:p=“http://www.springframework.org/schema/p”

<!--通过p名称空间来配置bean
    将光标放在p这个位置, 输入alt+enter, 就会自动的添加xmlns. 
    有时需要多来几次, 有个识别的过程
-->
<bean class="com.zzw.spring.bean.Monster" id="monster06"
      p:monsterId="400"
      p:name="天蓬元帅"
      p:skill="掌管十万天军"
/>

演示通过p名称空间来设置属性

public class SpringBeanTest {
    @Test
    public void setBeanByP() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        Monster monster06 = ioc.getBean("monster06", Monster.class);
        System.out.println("monster06=" + monster06);
    }
}

💖通过ref配置bean

引用注入其它bean对象

在spring的ioc容器, 可以通过ref来实现bean对象的相互引用[ref全称: reference]

<!--配置MemberDaoImpl对象-->
<bean class="com.zzw.spring.dao.MemberDaoImpl" id="memberDao"/>
<!--
    配置MemberServiceImpl对象
    1.ref="memberDao"表示 MemberServiceImpl对象属性memberDao引用的对象是id="memberDao"的对象
    2.这里就体现出spring容器的依赖注入
    3.注意: 在spring容器中, 它是作为一个整体来执行的, 即如果引用到了一个bean对象, 对配置的顺序没有要求
    4.建议还是按顺序. 好处是在阅读的时候, 比较方便
-->
<bean class="com.zzw.spring.service.MemberServiceImpl" id="memberService">
    <property name="memberDao" ref="memberDao"/>
</bean>
package com.zzw.spring.service;

public class MemberServiceImpl {
    private MemberDaoImpl memberDao;

    public MemberDaoImpl getMemberDao() {
        return memberDao;
    }

    public void setMemberDao(MemberDaoImpl memberDao) {
        this.memberDao = memberDao;
    }

    public void add() {
        System.out.println("MemberServiceImpl add方法被调用...");
        memberDao.add();
    }
}
package com.zzw.spring.dao;

public class MemberDaoImpl {
    public MemberDaoImpl() {
        System.out.println("MemberDaoImpl 构造器...");
    }

    public void add() {
        System.out.println("MemberDaoImpl add方法被执行");
    }
}

测试: 通过ref来设置bean属性

public class SpringBeanTest {
    @Test
    public void setBeanByRef() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        MemberServiceImpl memberService = ioc.getBean("memberService", MemberServiceImpl.class);
        memberService.add();
    }
}

Spring系列二:基于注解配置bean【建议收藏】,Spring5,spring,python,hive

💖通过内部bean配置属性

引用/注入内部bean对象

在spring的ioc容器, 可以直接配置内部bean对象

<!--配置MemberServiceImpl对象-使用内部bean-->
<bean class="com.zzw.spring.service.MemberServiceImpl" id="memberService2">
    <!--自己配置一个内部bean-->
    <property name="memberDao">
        <bean class="com.zzw.spring.dao.MemberDaoImpl"/>
    </property>
</bean>

通过内部bean, 设置属性

public class SpringBeanTest {
    @Test
    public void setBeanByPro() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        MemberServiceImpl memberService2 = ioc.getBean("memberService2", MemberServiceImpl.class);
        memberService2.add();
    }
}

💖对集合数组属性进行配置

引用/注入 集合/数据类型

  1. 主要掌握List / Map / Properties 三种集合的使用
  2. Properties是Hashtable的子类, 是key-value的形式
  3. 这里的properties的k-v, 都是String类型

在spring的ioc容器中, 如何给bean对象的 集合/数组 类型的属性赋值

public class Master {
    private String name;//主人名字
    private List<Monster> monsterList;
    private Map<String, Monster> monsterMap;
    private Set<Monster> monsterSet;

    //数组
    private String[] monsterName;

    //Java基础
    //这个Properties 是HashMap的子类, 是key-value的存放形式
    //这里Properties key和value 都是String
    private Properties properties;

	//getter, setter方法
}

给集合/数组属性进行赋值

public class SpringBeanTest {
    @Test
    public void setBeanByCollection() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        Master master = ioc.getBean("master", Master.class);
        System.out.println("master=" + master);
    }
}

💕对List属性进行配置

<!--配置Master对象
体会spring容器配置的特点 依赖注入
-->
<bean class="com.zzw.spring.bean.Master" id="master">
    <property name="name" value="太上老君"/>
    <!--给list属性赋值-->
    <property name="monsterList">
        <list>
            <!--引用的方式加入的-->
            <ref bean="monster03"/>
            <ref bean="monster04"/>
            <!--内部bean, 不再建议id-->
            <bean class="com.zzw.spring.bean.Monster"
                  p:monsterId="300"
                  p:name="狮驼岭"
                  p:skill="紫金葫芦"
            />
        </list>
    </property>
</bean>

💕对Map属性进行配置

<!--配置Master对象
体会spring容器配置的特点 依赖注入 非常灵活
-->
<bean class="com.zzw.spring.bean.Master" id="master">
    <property name="name" value="太上老君"/>
    <!--给map属性赋值-->
    <property name="monsterMap">
        <map>
            <entry>
                <key>
                    <value>monster04</value>
                </key>
                <!--这里使用的是外部的bean, 引入-->
                <ref bean="monster04"/>
            </entry>
            <entry>
                <key>
                    <value>monster03</value>
                </key>
                <!--内部bean, 不再建议id-->
                <bean class="com.zzw.spring.bean.Monster"
                      p:monsterId="300"
                      p:name="狮驼岭"
                      p:skill="紫金葫芦~"
                />
            </entry>
        </map>
    </property>
</bean>

💕对Set属性进行配置

<!--配置Master对象
体会spring容器配置的特点 依赖注入 非常灵活
-->
<bean class="com.zzw.spring.bean.Master" id="master">
    <property name="name" value="太上老君"/>
    <!--给set属性赋值-->
    <property name="monsterSet">
        <set>
            <!--这里使用的是外部的bean, 引入-->
            <ref bean="monster05"/>
            <ref bean="monster06"/>
            <!--内部bean, 不再建议id-->
            <bean class="com.zzw.spring.bean.Monster"
                  p:monsterId="300"
                  p:name="狮驼岭"
                  p:skill="紫金葫芦~"
            />
        </set>
    </property>
</bean>

💕对Array属性进行配置

<!--配置Master对象
体会spring容器配置的特点 依赖注入 非常灵活
-->
<bean class="com.zzw.spring.bean.Master" id="master">
    <property name="name" value="太上老君"/>
    <!--给数组属性赋值
    补充: array标签中使用 value 还是 bean, ref ...要根据业务来决定
    这里的monsterName是字符串
    -->
    <property name="monsterName">
        <array>
            <value>六耳猕猴</value>
            <value>东海龙王</value>
            <value>红孩儿</value>
        </array>
    </property>
</bean>

💕对Properties属性进行配置

<!--配置Master对象
体会spring容器配置的特点 依赖注入 非常灵活
-->
<bean class="com.zzw.spring.bean.Master" id="master">
    <property name="name" value="太上老君"/>
    <!--对properties属性进行赋值 结构k(String)-v(String) -->
    <property name="properties">
        <props>
            <prop key="username">root</prop>
            <prop key="password">123456</prop>
            <prop key="email">978964140@qq.com</prop>
        </props>
    </property>
</bean>

💖使用utillist进行配置

spring的ioc容器, 可以通过util名称空间来创建list集合

public class BookStore {
    //书
    private List<String> bookList;

    //无参构造器, 如果没有其它的构造器, 该无参构造器可以不写
    //如果有其它的构造器, 则必须显示地定义一下无参构造器
    public BookStore() {
    }

	//getter, setter方法
}

beans.xml

<!--定义一个util:list, 并且指定了id 可以达到数据复用
说明: 在使用util:list 名称空间的时候, 需要引入相应的标签, 一般来说通过alt+enter会自动加入
, 如果没有就手动添加一下
-->
<util:list id="myBookList">
    <value>三体</value>
    <value>时间简史</value>
    <value>梦的解析</value>
    <value>福尔摩斯探案集</value>
</util:list>

<!--配置BookStore对象-->
<bean class="com.zzw.spring.bean.BookStore" id="bookStore">
    <property name="bookList" ref="myBookList"/>
</bean>

使用util:list名称空间给属性赋值

public class SpringBeanTest {
    @Test
    public void setBeanByUtilList() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        BookStore bookStore = ioc.getBean("bookStore", BookStore.class);
        System.out.println("bookStore=" + bookStore);
    }
}

💖属性级联赋值配置

spring的ioc容器, 可以直接给对象属性的属性赋值, 即级联属性赋值

部门

public class Dept {
    private String name;

    public Dept() {
    }

	//getter, setter方法

员工

public class Employee {
    private String name;
    private Dept dept;

    public Employee() {
    }
	
	//getter, setter方法
}

beans.xml

<!--配置Dept对象-->
<bean class="com.zzw.spring.bean.Dept" id="dept"/>
<!--配置Employee对象-->
<bean class="com.zzw.spring.bean.Employee" id="employee">
    <property name="name" value="tom"/>
    <property name="dept" ref="dept"/>
    <!--这里我希望给dept的name属性指定值[级联属性赋值]-->
    <property name="dept.name" value="java开发"/>
</bean>

给属性进行级联赋值

public class SpringBeanTest {
    @Test
    public void setBeanByRelation() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        Employee employee = ioc.getBean("employee", Employee.class);
        System.out.println("employee=" + employee);
    }
}

💖通过静态工厂获取bean

在spring的ioc容器, 可以通过静态工厂获取bean对象

这是一个静态工厂类-可以返回Monster对象

package com.zzw.spring.factory;

public class MyStaticFactory {
    private static Map<String, Monster> monsterMap;

    //使用static代码块进行初始化 - java基础
    static {
        monsterMap = new HashMap<>();
        monsterMap.put("monster01", new Monster(100, "齐天大圣", "如意金箍棒"));
        monsterMap.put("monster02", new Monster(200, "天蓬元帅", "九齿钉耙"));
    }

    //提供一个方法, 返回Monster对象
    public static Monster getMonster(String key) {
        return monsterMap.get(key);
    }
}
<!--配置Monster对象, 通过静态工厂获取
解读
1.通过静态工厂获取bean
2.class 是静态工厂类的全路径
3.factory-method 表示是指定静态工厂类的哪个方法返回对象
4.constructor-arg value="monster02" value是指定要返回静态工厂的哪一个对象
-->
<bean class="com.zzw.spring.factory.MyStaticFactory" id="myMonster01"
      factory-method="getMonster">
    <constructor-arg value="monster02"/>
</bean>

通过静态工厂获取bean

public class SpringBeanTest {
    @Test
    public void getBeanByStaticFactory() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        Monster myMonster01 = ioc.getBean("myMonster01", Monster.class);
        Monster myMonster02 = ioc.getBean("myMonster01", Monster.class);
        System.out.println("myMonster01=" + myMonster01);
        System.out.println(myMonster01 == myMonster02);//true. myMonster01和myMonster02是同一个对象
    }
}

💖bean配置信息重用

在spring的ioc容器, 提供了一种继承的方式来实现bean配置信息的重用

<!--配置Monster对象-->
<bean class="com.zzw.spring.bean.Monster" id="monster10"
      p:monsterId="10"
      p:name="蜘蛛侠"
      p:skill="吐丝"
/>
<!--
    1.配置Monster对象,
    2.但是这个对象的属性值和id="monster10"对象的属性值一样
    3.parent="monster10" 指定当前这个配置的对象的属性值从 id="monster10"的对象来
-->
<bean class="com.zzw.spring.bean.Monster" id="monster11" parent="monster10"/>


<!--配置Monster对象
1.如果bean指定了 abstract=true, 表示该bean对象, 是用于被继承
2.本身这个bean就不能被获取/实例化
-->
<bean class="com.zzw.spring.bean.Monster" id="monster12" abstract="true"
      p:monsterId="12"
      p:name="蜘蛛侠~"
      p:skill="吐丝~"
/>
<bean id="monster13" class="com.zzw.spring.bean.Monster" parent="monster12"/>

通过继承, 配置bean

public class SpringBeanTest {
    @Test
    public void getBeanByExtends() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        
        Monster monster11 = ioc.getBean("monster11", Monster.class);
        System.out.println("monster11=" + monster11);

        Monster monster13 = ioc.getBean("monster13", Monster.class);
        System.out.println("monster13=" + monster13);
    }
}

💖bean创建顺序

在spring的ioc容器, 默认是按照配置的顺序创建bean对象

测试bean创建顺序

实验1

<!--测试bean对象的创建顺序
1.在默认情况下, bean创建的顺序是按照配置顺序来的
2.但是如果我们增加了 depends-on="department01" 这时就会先创建id=department01这个对象
-->
<bean class="com.zzw.spring.bean.Student" id="student01"/>
<bean class="com.zzw.spring.bean.Department" id="department01"/>
public class SpringBeanTest {
    @Test
    public void testBeanCreateOrder() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");

        System.out.println("ok~");
    }
}
public class Department {
    public Department() {
        System.out.println("Department构造器 被执行");
    }
}
public class Student {
    public Student() {
        System.out.println("Student构造器 被执行");
    }
}

※会先创建student01这个bean对象, 然后创建department01这个bean对象

运行结果

Student构造器 被执行
Department构造器 被执行
ok~

※如果这样配置, 会先创建department01对象, 再创建student01对象

<!--测试bean对象的创建顺序
1.在默认情况下, bean创建的顺序是按照配置顺序来的
2.但是如果我们增加了 depends-on="department01" 这时就会先创建id=department01这个对象
-->
<bean class="com.zzw.spring.bean.Student" id="student01" depends-on="department01"/>
<bean class="com.zzw.spring.bean.Department" id="department01"/>

运行结果

Department构造器 被执行
Student构造器 被执行
ok~

实验2
1.先看下面的配置, 请问两个bean创建的顺序是什么? 并分析执行流程

<!--配置MemberDaoImpl对象-->
<bean class="com.zzw.spring.dao.MemberDaoImpl" id="memberDao"/>

<bean class="com.zzw.spring.service.MemberServiceImpl" id="memberService">
    <property name="memberDao" ref="memberDao"/>
</bean>

答案:
1)先创建 id=memberDao
2)再创建 id=memberService
3)调用 memberService.setMemberDao() 完成引用


运行结果:

MemberDaoImpl 构造器...
MemberServiceImpl 构造器被执行
setMemberDao()...

2.先看下面的配置, 请问两个bean创建的顺序是什么? 并分析执行流程

<bean class="com.zzw.spring.service.MemberServiceImpl" id="memberService">
    <property name="memberDao" ref="memberDao"/>
</bean>

<!--配置MemberDaoImpl对象-->
<bean class="com.zzw.spring.dao.MemberDaoImpl" id="memberDao"/>

答案:
1)先创建 id=memberService
2)再创建 id=memberDao
3)调用 memberService.setMemberDao() 完成引用


运行结果

MemberServiceImpl 构造器被执行
MemberDaoImpl 构造器...
setMemberDao()...

💖bean的单例和多实例

在spring的ioc容器中, 默认情况下是按照单例创建的. 即配置一个bean对象后, ioc容器只会创建一个bean对象
如果我们希望ioc容器配置的某个bean对象, 是以多个实例形式创建的. 则可以通过配置 scope=“prototype” 来指定

public class Cat {
    private Integer id;
    private String name;
    
    public Cat() {
    //getter, setter方法
}
<!--配置Cat对象
1.在默认情况下, scope属性是 scope="singleton"
2.在ioc容器中, 只会有一个这样的bean对象
3.当程序员执行getBean时, 返回的是同一个对象
4.如果我们希望每次返回一个新的bean对象, 则可以这样配置 scope="prototype"
5.如果bean的配置是 scope="singleton" lazy-init="true" 这时, ioc容器就不会提前创建该对象
  , 而是当执行getBean方法的时候, 才会创建对象
-->
<bean class="com.zzw.spring.bean.Cat" id="cat" scope="prototype" lazy-init="true">
    <property name="id" value="100"/>
    <property name="name" value="花喵"/>
</bean>

测试Scope

@Test
public void testBeanScope() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    Cat cat1 = ioc.getBean("cat", Cat.class);
    Cat cat2 = ioc.getBean("cat", Cat.class);
    Cat cat3 = ioc.getBean("cat", Cat.class);
    System.out.println("cat1=" + cat1);
    System.out.println("cat2=" + cat2);
    System.out.println("cat3=" + cat3);
}

使用细节
1)bean默认是单例singleton; 在启动容器时, bean默认就会创建, 并放入到singletonObjects
2) 当<bean scope=“prototype”>设置为多实例机制后, 该bean是在getBean()时被创建
3) 如果是单例singleton, 同时希望在getBean时才创建, 可以指定懒加载 lazy-init="true"(注意默认是false)
4) 通常情况下, lazy-init 就使用默认值false. 在开发看来, 空间换时间是值得的, 除非有特殊要求
5) 如果scope=“prototype”, 这时你的lazy-init 属性的值不管是true还是false, 都是在getBean的时候才创建这个对象

💖bean的生命周期

bean对象创建是由JVM完成的, 然后执行如下方法

  1. 执行构造器
  2. 执行set相关方法
  3. 调用bean的初始化方法(需要配置)
  4. 使用bean
  5. 当容器关闭的时候, 调用bean的销毁方法(需要配置)
public class House {
    private String name;

    public House() {
        System.out.println("House构造器 被执行...");
    }

    public void setName(String name) {
        System.out.println("House setName()=" + name);
        this.name = name;
    }

    //解读
    //1.这个方法是由程序员来编写的
    //2.根据自己的业务逻辑来写.
    //3.名字也不是固定的
    public void init() {
        System.out.println("House init()....");
    }

    //解读
    //1.这个方法是由程序员来编写的
    //2.根据自己的业务逻辑来写.
    //3.名字也不是固定的
    public void destroy() {
        System.out.println("House destroy()...");
    }
}
<!--配置House对象, 演示整个bean的生命周期
解读
1.init-method="init" 指定bean的初始化方法, 在setter方法后执行
2.init方法执行的时机, 由spring容器控制
3.destroy-method="destroy" 指定bean的销毁方法, 在容器关闭的时候执行
4.destroy方法执行的时机, 由spring容器控制
-->
<bean class="com.zzw.spring.bean.House" id="house"
      init-method="init" destroy-method="destroy">
    <property name="name" value="上海豪宅"/>
</bean>

测试bean的生命周期

public class SpringBeanTest {
    @Test
    public void testBeanLife() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        House house = ioc.getBean("house", House.class);
        System.out.println("house=" + house);

        //关闭容器
        //1.ioc的编译类型 ApplicationContext, 运行类型 ClassPathXmlApplicationContext
        //2.因为ClassPathXmlApplicationContext 实现了 ConfigurableApplicationContext
        //3.ClassPathXmlApplicationContext 是有close()的
        //4.将ioc 转成ClassPathXmlApplicationContext, 再调用close()
        //ioc.close()
        //5.关闭ioc容器
        ((ClassPathXmlApplicationContext) ioc).close();
    }
}

输出

House构造器 被执行...
House setName()=上海豪宅
House init()....
setMemberDao()...
house=com.zzw.spring.bean.House@327bcebd
House destroy()...

使用细节
1.初始化init方法和destroy方法, 由程序员来指定
2.销毁方法就是当关闭容器时, 才会被调用

💖配置bean后置处理器

1在spring的ioc容器, 可以配置bean的后置处理器
2.该 处理器/对象 会在bean初始化方法调用前和初始化方法调用后被调用
3.bean中没有声明初始化方法, 后置处理器依然会发生作用
3.程序员可以在后置处理器中编写自己的代码

package com.zzw.spring.bean;

//ctrl+h 可以查看类的继承关系
//这是一个后置处理器, 需要实现 BeanPostProcessor接口
public class MyBeanPostProcessor implements BeanPostProcessor {
    /**
     * 什么时候被调用: 在Bean的init方法前被调用
     * @param bean     传入在IOC容器中 创建/配置 的bean
     * @param beanName 传入在IOC容器中 创建/配置 的bean的id
     * @return Object 是程序员对传入的bean进行修改/处理[如果有需要的话], 返回
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization()... bean="
                + bean + " beanName=" + beanName);
        return bean;
    }

    /**
     * 什么时候被调用: 在Bean的init方法后被调用
     * @param bean     传入在IOC容器中 创建/配置 的bean
     * @param beanName 传入在IOC容器中 创建/配置 的bean的id
     * @return Object 是程序员对传入的bean进行修改/处理[如果有需要的话], 返回
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization()... bean="
                + bean + " beanName=" + beanName);
        return bean;
    }
}

新建beans02.xml配置文件

<!--配置House对象-->
<bean class="com.zzw.spring.bean.House" id="house"
      init-method="init"
      destroy-method="destroy">
    <property name="name" value="大豪宅"/>
</bean>

<!--配置后置处理器对象
解读:
1.当我们在beans02.xml 容器配置文件, 配置了MyBeanPostProcessor
2.这时后置处理器对象, 就会作用在该容器创建的所有bean对象
-->
<bean class="com.zzw.spring.bean.MyBeanPostProcessor" id="beanPostProcessor"/>

测试

package com.zzw.spring.test;

public class SpringBeanTest {

    @Test
    public void testBeanPostProcessor() {
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("beans02.xml");
        House house = ioc.getBean("house", House.class);
        System.out.println("使用house=" + house);
        //关闭容器
        //ioc不能调用子类的特有的成员
        //因为在编译阶段, 能调用哪些成员, 是由编译类型来决定的
        //ioc编译类型 ApplicationContext, 运行类型 ClassPathXmlApplicationContext
        ((ClassPathXmlApplicationContext) ioc).close();//向下转型
    }
}

其它说明
1.怎么执行到这个方法? => 使用AOP(反射+动态代理+IO+容器+注解)
2.有什么用? => 可以对IOC容器中所有的对象进行统一处理, 比如日志处理/权限校验/安全验证/事务管理.
-初步体验案例: 如果类型是House的统一改成 上海豪宅
3.针对容器的所有对象吗? 是的=>切面编程
4.后面我们会自己实现这个底层机制
5.这是一个比较难以理解的知识点.

<!--配置House对象-->
<bean class="com.zzw.spring.bean.House" id="house"
      init-method="init"
      destroy-method="destroy">
    <property name="name" value="大豪宅"/>
</bean>

<bean class="com.zzw.spring.bean.House" id="house02"
      init-method="init"
      destroy-method="destroy">
    <property name="name" value="宫殿"/>
</bean>

<!--配置后置处理器对象
解读:
1.当我们在beans02.xml 容器配置文件, 配置了MyBeanPostProcessor
2.这时后置处理器对象, 就会作用在该容器的创建的bean对象
3.已经是针对所有对象编程->切面编程AOP
-->
<bean class="com.zzw.spring.bean.MyBeanPostProcessor" id="beanPostProcessor"/>
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization()... bean="
                + bean + " beanName=" + beanName);
        //对多个对象进行处理/编程=>切面编程
        if (bean instanceof House) {
            ((House) bean).setName("上海豪宅~");
        }
        //这里返回一个空值并不会有任何影响
        //return null;
        return bean;
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization()... bean="
                + bean + " beanName=" + beanName);
        return bean;
    }
}
public class SpringBeanTest {
    @Test
    public void testBeanPostProcessor() {
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("beans02.xml");
        House house = ioc.getBean("house", House.class);
        House house02 = ioc.getBean("house02", House.class);
        System.out.println("使用house=" + house);
        System.out.println("使用house=" + house02);
        //关闭容器
        //ioc不能调用子类的特有的成员
        //因为在编译阶段, 能调用哪些成员, 是由编译类型来决定的
        //ioc编译类型 ApplicationContext, 运行类型 ClassPathXmlApplicationContext
        ((ClassPathXmlApplicationContext) ioc).close();//向下转型
    }
}

测试结果(return bean和return null都是下面的输出结果)

House构造器 被执行...
House setName()=大豪宅
postProcessBeforeInitialization()... bean=House{name='大豪宅'} beanName=house
House setName()=上海豪宅~
House init()....
postProcessAfterInitialization()... bean=House{name='上海豪宅~'} beanName=house
House构造器 被执行...
House setName()=宫殿
postProcessBeforeInitialization()... bean=House{name='宫殿'} beanName=house02
House setName()=上海豪宅~
House init()....
postProcessAfterInitialization()... bean=House{name='上海豪宅~'} beanName=house02
使用house=House{name='上海豪宅~'}
使用house=House{name='上海豪宅~'}
House destroy()...
House destroy()...

💖通过属性文件配置bean

在spring的ioc容器, 通过属性文件给bean注入值

在src目录下, 新建配置文件my.properties [配置文件都要写在src目录下]

monsterId=1000
name=\u5343\u5e74\u9f9f 
skill=\u65cb\u8f6c\u6253\u51fb

解决中文乱码问题
Spring系列二:基于注解配置bean【建议收藏】,Spring5,spring,python,hive

<!--指定属性文件
说明
1.先把文件修改成提示All Problem, 在右上角
2.提示错误, 将光标放在context 输入alt+enter, 就会自动引入namespace
3.location="classpath:my.properties" 表示指定属性文件的位置
4.提示, 需要带上 classpath
-->
<context:property-placeholder location="classpath:my.properties"/>

<!--配置monster对象
1.通过属性文件给monster对象的属性赋值
2.这时我们的属性值, 通过${属性名}
3.这里说的 属性名, 就是 my.properties文件中的 k=v 的k
-->
<bean class="com.zzw.spring.bean.Monster" id="monster100">
    <property name="monsterId" value="${monsterId}"/>
    <property name="name" value="${name}"/>
    <property name="skill" value="${skill}"/>
</bean>
public class SpringBeanTest {

    //通过属性文件给bean属性赋值
    @Test
    public void setBeanByFile() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans03.xml");
        Monster monster100 = ioc.getBean("monster100", Monster.class);
        System.out.println("monster100=" + monster100);
    }
}

💖基于XML的bean的自动装配

在spring的ioc容器, 可以实现自动装配bean

这里说的Action就是我们前面学习过的Servlet -> 充当Controller
Dao

package com.zzw.spring.dao;

public class OrderDao { //DAO类
    public void saveOrder() {
        System.out.println("保存一个订单....");
    }
}

Service

package com.zzw.spring.service;

public class OrderService { //Service类

    //OrderDao属性
    private OrderDao orderDao;

    //getter方法
    public OrderDao getOrderDao() {
        return orderDao;
    }

    //setter方法
    public void setOrderDao(OrderDao orderDao) {
        this.orderDao = orderDao;
    }
}

Action

package com.zzw.spring.web;

public class OrderAction { //Servlet就是Controller
    //OrderService属性
    private OrderService orderService;
    
    //getter方法
    public OrderService getOrderService() {
        return orderService;
    }
    
    //setter方法
    public void setOrderService(OrderService orderService) {
        this.orderService = orderService;
    }
}

bean03.xml

<!--配置OrderDao对象-->
<bean class="com.zzw.spring.dao.OrderDao" id="orderDao"/>
<!--配置OrderService对象
解读:
1.autowire="byType" 表示 在创建orderService时,
  通过类型的方式给对象的属性 自动完成赋值/引用
2.比如OrderService对象有 private OrderDao orderDao
3.就会在容器中去找有没有 OrderDao类型对象
4.如果有, 就会自动地装配. 提示: 如果是按照 byType 方式来装配, 这个容器中不能有两个
  OrderDao类型的对象
5.如果你的对象没有属性, autowire就没有必要写
6.其它类推...
-->
<bean autowire="byType" class="com.zzw.spring.service.OrderService"
      id="orderService"/>
<!--配置OrderAction对象-->
<bean autowire="byType" class="com.zzw.spring.web.OrderAction" id="orderAction"/>

通过自动装配来对属性赋值

//通过自动装配来对属性赋值
public class SpringBeanTest {
    @Test
    public void setBeanByAutowire() {
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("beans03.xml");

        OrderAction orderAction = ioc.getBean("orderAction", OrderAction.class);

        //验证是否自动装配上OrderService
        System.out.println(orderAction.getOrderService());
        //验证是否自动装配上OrderDao
        System.out.println(orderAction.getOrderService().getOrderDao());
    }
}

byName方式讲解

<!--
7.如果我们设置的是 autowire="byName" 表示通过名字完成自动装配
8.比如下面的 autowire="byName" class="com.zzw.spring.service.OrderService"
  1) 先看 OrderService 属性 private OrderDao orderDao;
  2) 再根据这个属性的setXxx()方法的 xxx 来找对象id
  3) public void setOrderDao() 就会找 id=orderDao对象来进行自动装配
  4) 如果没有就装配失败
-->
<bean autowire="byName" class="com.zzw.spring.service.OrderService"
      id="orderService"/>
<!--配置OrderAction对象-->
<bean autowire="byName" class="com.zzw.spring.web.OrderAction"
      id="orderAction"/>

💖Spring El 表达式配置Bean

1.Spring Expression Language, Spring表达式语言, 简称SpEL. 支持运行时查询并可以操作对象.
2.和EL表达式一样, SpEL根据JavaBean风格的getXxx(), setXxx()方法定义的属性访问对象
3.SpEL使用#{…}作为界定符, 所有在大括号中的字符都被认为是SpEL表达式
4.不是重点, 能看懂即可.

public class SpELBean {
    private String name;
    private Monster monster;
    private String monsterName;
    private String crySound;
    private String bookName;
    private Double reuslt;

    public SpELBean() {
    }
    
    //普通方法, 返回字符串
    public String cry(String crySound) {
        return "发出 " + " 的声音";
    }

    //静态方法 返回字符串
    public static String read(String bookName) {
        return "正在读" + bookName;
    }

	//getter方法, setter方法
	
    @Override
    public String toString() {
        return "SpELBean{" +
                "name='" + name + '\'' +
                "\nmonster=" + monster +
                "\nmonsterName='" + monsterName + '\'' +
                "\ncrySound='" + crySound + '\'' +
                "\nbookName='" + bookName + '\'' +
                "\nreuslt=" + reuslt +
                '}';
    }
}

beans04.xml

<!--配置一个monster对象-->
<bean class="com.zzw.spring.bean.Monster" id="monster01"
      p:monsterId="001"
      p:name="齐天大圣"
      p:skill="金箍棒"
/>

<!--spring el 表达式使用
解读
1.通过spEl给bean的属性赋值
-->
<bean class="com.zzw.spring.bean.SpELBean" id="spELBean">
    <!--sp el 给字面量-->
    <property name="name" value="#{'赵志伟'}"/>
    <!--sp el 引用其它bean-->
    <property name="monster" value="#{monster01}"/>
    <!--sp el 引用其它bean的属性值-->
    <property name="monsterName" value="#{monster01.name}"/>
    <!--sp el 调用普通方法(返回值) 赋值-->
    <property name="crySound" value="#{spELBean.cry('小猫')}"/>
    <!--sp el 调用静态方法(返回值) 赋值-->
    <property name="bookName" value="#{T(com.zzw.spring.bean.SpELBean).read('安乐传')}"/>
    <!--sp el 通过运算赋值-->
    <property name="reuslt" value="#{72+53*33.8}"/>
</bean>
//通过spring el 对属性赋值
public class SpringBeanTest {
    @Test
    public void setBeanBySpEl() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans04.xml");
        SpELBean spELBean = ioc.getBean("spELBean", SpELBean.class);
        System.out.println("spELBean=" + spELBean);
    }
}

测试结果

spELBean=SpELBean{name='赵志伟'
monster=Monster{monsterId='1', name='齐天大圣', skill='金箍棒'}
monsterName='齐天大圣'
crySound='发出 小猫 的声音'
bookName='正在读安乐传'
reuslt=1863.3999999999999}

Spring系列二:基于注解配置bean【建议收藏】,Spring5,spring,python,hive
下乘: Spring系列三:基于注解配置bean文章来源地址https://www.toymoban.com/news/detail-626752.html

到了这里,关于Spring系列二:基于注解配置bean【建议收藏】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Spring进阶系列丨第六篇】Spring的Bean管理(基于注解)

    回顾一下 基于xml配置的Spring对Bean的管理 ,对Bean的完整管理如下所示: 分析可以发现:我们对Bean的管理就四个方面,分别是: 用于创建对象的 用于注入数据的 用于改变Bean的作用域的 和Bean的生命周期相关的 其实对于注解来说,也是包括了这四个方面,换句话说, 使用注

    2024年02月03日
    浏览(47)
  • Spring——事务注解@Transactional【建议收藏】

    在某些业务场景下,如果一个请求中,需要同时写入多张表的数据或者执行多条sql,为了保证操作的原子性(要么同时成功,要么同时失败),避免数据不一致的情况,我们一般都会用到事务;Spring框架下,我们经常会使用@Transactional注解来管理事务; 本篇介绍Spring的事务注

    2024年02月03日
    浏览(47)
  • 一起学SF框架系列5.8-spring-Beans-Bean注解解析3-解析配置component-scan

    本文主要讲述Spring是如何解析“context:component-scan”元素,扫描加载目录下的BeanDefinition。 1、解析的元素如下: 注:该元素解析过程中,会自动处理“context:annotation-config/”元素要解析的内容。 2、只扫描加载目录下的BeanDefinition,不对注解进行解析。在AbstractApplicationContext.

    2024年02月16日
    浏览(39)
  • 【深入浅出Spring原理及实战】「夯实基础系列」360全方位渗透和探究Spring的核心注解开发和实现指南(Spring5的常见的注解)

    Spring 5.x中常见的注解包括@Controller、@Service、@Repository。当我们研究Spring Boot源码时,会发现实际上提供了更多的注解。了解这些注解对于我们非常重要,尽管目前可能还用不到它们。 注解 功能 @Bean 器中注册组件,代替来的标签 @Configuration 声明这是一个配置类,替换以前的配

    2024年02月16日
    浏览(46)
  • Spring5系列学习文章分享---第一篇(概述+特点+IOC原理+IOC并操作之bean的XML管理操作)

    开篇: 欢迎来到 Spring 5 学习系列!在这个系列中,我们将深入研究 Spring 框架的最新版本,揭示其在现代Java开发中的精髓。无论你是初学者还是有经验的开发者,本系列都旨在为你提供深刻的理解和实用的知识,让你在构建强大、可维护和高效的应用程序方面更上一层楼。

    2024年01月22日
    浏览(77)
  • Spring5学习随笔-高级注解(@ComponentScan、@Configuration.....),替换XML配置文件

    学习视频:【孙哥说Spring5:从设计模式到基本应用到应用级底层分析,一次深入浅出的Spring全探索。学不会Spring?只因你未遇见孙哥】 Spring在3.x提供的新的注解,用于替换XML配置文件。 问题 : 配置Bean在应用的过程中替换了XML具体的什么内容? AnnotationConfigApplicationContext 配

    2024年02月05日
    浏览(45)
  • Spring系列二:基于XML配置bean

    上文中, 我们学习到了 Spring系列一:spring的安装与使用 接下来我们学习, 通过XML配置bean Bean管理包括两方面: 创建bean对象, 给bean注入属性 案例: 通过spring的ioc容器, 获取一个bean对象, 获取方式: 按类型. 演示通过bean的类型获取对象 细节 按照类型获取bean, 要求ioc容器中的同一个

    2024年02月14日
    浏览(37)
  • Spring5框架——AOP操作:通过Aspectj注解方式和配置文件方式来实现

    o((⊙﹏⊙))o. ** 之前的博客介绍了什么是AOP,以及AOP的底层原理,AOP主要是在原本的基础上添加一些之外的功能但是添加的功能是不会修改原定的代码,接下来为你介绍的是Aspectj注解,Spring 框架一般都是基于 AspectJ 实现 AOP 操作。AspectJ 不是 Spring 组成部分,独立 AOP 框架,一

    2024年02月16日
    浏览(50)
  • 【Spring进阶系列丨第四篇】学习Spring中的Bean管理(基于xml配置)

    在之前的学习中我们知道,容器是一个空间的概念,一般理解为可盛放物体的地方。在Spring容器通常理解为BeanFactory或者ApplicationContext。我们知道spring的IOC容器能够帮我们创建对象,对象交给spring管理之后我们就不用手动去new对象。 那么Spring是如何管理Bean的呢? 简而言之,

    2024年02月05日
    浏览(65)
  • 【Spring框架全系列】方法注解@Bean的使用

    📬📬哈喽,大家好,我是小浪。上篇博客我们介绍了五大类注解的使用方法,以及如何解决Spring使用五大类注解生成bean-Name的问题;那么,谈到如何更简单的读取和存储对象,这里我们还需要介绍另外一个\\\"方法注解@Bean\\\"的使用,快来一起学习叭!🛳🛳 📲目录 一、如何使

    2024年02月04日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包