2-SpringBean管理

目录 G:\8-CodeCloud\spring
项目名称 spring_ioc
项目文件夹 com.imooc.ioc.demo2;com.imooc.ioc.demo3;com.imooc.ioc.demo4
项目名称 spring_ioc_annotation
项目文件夹 com.imooc.ioc.demo1;com.imooc.ioc.demo2;com.imooc.ioc.demo3;

1. SpringBean管理的方式:XML方式

1.1 Bean配置方式

  1. 采用无参数的构造方法的方式
  2. 采用静态工厂实例化的方式
  3. 实例工厂实例化的方式

applicationContext.xml配置如下:

    <!--demo2 Bean 的实例化的三种方式-->
    <!--第一种:无参构造器方式-->
    <bean id="bean1" class="com.imooc.ioc.demo2.Bean1" />
    <!--第二种:静态工厂的方式-->
    <bean id="bean2" class="com.imooc.ioc.demo2.Bean2Factory" factory-method="createBean2"/>
    <!--第三种:实例工厂的方式-->
    <bean id="bean3Factory" class="com.imooc.ioc.demo2.Bean3Factory"/>
    <bean id="bean3" factory-bean="bean3Factory" factory-method="createBean3"/>

但实际工作中基本都是无参数的构造方法方式,其余2种方式意义不大。

1.2 Bean配置详解

(1)id与name
    <bean id="bean1" class="com.imooc.ioc.demo2.Bean1" />
    <bean name="bean1@" class="com.imooc.ioc.demo2.Bean1" />

区别在于name中可以有特殊字符。

(2)bean的作用域
Bean的作用域.png

实验如下:通过打印对象地址来区分是否是同一对象

    @Test
    public void  demo1(){
        //创建工厂
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过工厂获得类的实例
        Person person1 = (Person) applicationContext.getBean("person");
        Person person2 = (Person) applicationContext.getBean("person");

        System.out.println(person1);
        System.out.println(person2);
    }

(3)bean的生命周期

具体配置如下:

    <bean id="man" class="com.imooc.ioc.demo3.Man" init-method="setup" destroy-method="teardown"/>    

注意:
执行顺序 构造函数—>init-method—>destroy-method
destroy-method仅单例生效,并且只有在applicationContext工厂关闭的时候才会调用,工作中意义不大


完整的生命周期:
applicationContext2.xml中配置MyBeanPostProcessor

    <bean id="man" class="com.imooc.ioc.demo3.Man" init-method="setup" destroy-method="teardown">
        <property name="name" value="徐晓成"/>
    </bean>

    <bean class="com.imooc.ioc.demo3.MyBeanPostProcessor"/>

Man定义Spring Bean生命周期的步骤

package com.imooc.ioc.demo3;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class Man implements BeanNameAware,ApplicationContextAware,InitializingBean,DisposableBean{

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {

        System.out.println("第二步:设置属性");
        this.name = name;
    }

    public Man(){
        System.out.println("第一步:Man被实例化了");
    }

    public void setup(){
        System.out.println("第七步:Man被初始化了");

    }

    public void teardown(){
        System.out.println("第十一步:执行自己的销毁方法,Man被销毁了");
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("第三步:设置Bean的名称"+name);

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("第四步:了解工厂的信息");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("第六步:属性设置后");
    }

    public void run(){
        System.out.println("第九步:执行业务方法");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("第十步:执行Spring 销毁方法");
    }
}

MyBeanPostProcessor是Spring中重要的方法涉及后续的AOP,代码如下:

package com.imooc.ioc.demo3;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyBeanPostProcessor implements BeanPostProcessor{

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("第五步:初始化前方法......");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
        System.out.println("第八步:初始化后方法......");
            return bean;
    }
}

具体的生命周期如下:

  1. Spring调用类的构造函数实例化
  2. DI:通过类的set方法初始化属性
  3. setBeanName 设置bean的名称
  4. setApplicationContext 了解工厂的信息
  5. 调用 MyBeanPostProcessor.postProcessBeforeInitialization 初始化前方法
  6. afterPropertiesSet 属性设置后
  7. init-method(配置文件中配置),进行初始化
  8. 调用 MyBeanPostProcessor.postProcessAfterInitialization 初始化后方法
  9. 执行业务方法
  10. destroy执行Spring 销毁方法
  11. destroy-method(配置文件中配置)执行自己的销毁方法,对象被销毁了
(4)Bean的增强

新建UserDao.java

package com.imooc.ioc.demo3;

public class UserDaoImpl implements UserDao {

    @Override
    public void findAll() {
        System.out.println("查询用户。。。。");
    }

    @Override
    public void save() {
        System.out.println("保存用户。。。。");

    }

    @Override
    public void update() {
        System.out.println("修改用户。。。。");

    }

    @Override
    public void delete() {
        System.out.println("删除用户。。。。");

    }
}

改造MyBeanPostProcessor.java,对userDao的sava方法进行增强

package com.imooc.ioc.demo3;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyBeanPostProcessor implements BeanPostProcessor{

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("第五步:初始化前方法......");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
        System.out.println("第八步:初始化后方法......");

        if ("userDao".equals(beanName)) {

            Object proxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    if("save".equals(method.getName())){
                        System.out.println("权限校验");
                        return method.invoke(bean,args);
                    }
                    return method.invoke(bean,args);
                }
            });
            return proxy;

        }else {

            return bean;
        }

    }
}

(5)Bean的属性注入

构造函数属性注入:

    <!--Bean构造方法的属性注入,通过构造方法,在Bean实例化的时候对属性赋值-->
    <bean id="user" class="com.imooc.ioc.demo4.User">
        <constructor-arg name="name" value="徐晓成"/>
        <constructor-arg name="age" value="29"/>
    </bean>

set方法属性注入1

    <!--Bean的set方法的属性注入-->
    <bean id="person" class="com.imooc.ioc.demo4.Person">
        <property name="name" value="徐晓成"/>
        <property name="age" value="29"/>
    </bean>

set方法属性注入2

    <!--Bean的set方法的属性注入-->
    <bean id="person" class="com.imooc.ioc.demo4.Person">
        <property name="name" value="徐晓成"/>
        <property name="age" value="29"/>
        <property name="cat" ref="cat"/>
    </bean>

    <bean id="cat" class="com.imooc.ioc.demo4.Cat">
        <property name="name" value="ketty"/>
    </bean>

此外还有p名称空间属性注入、SpEL属性注入、复杂类型属性注入,由于工作中不常用就不记录了

2. SpringBean管理的方式:注解方式

2.1 Bean的管理

(1)开启注解扫描:如果下面的包中有注解就交给spring进行管理
    <!--开启注解扫描,告诉spring如果下面的包中有注解就交给spring进行管理-->
    <context:component-scan base-package="com.imooc"/>
(2)用注解代替XML文件定义Bean
使用注解定义bean.png
(3)用注解进行属性注入

属性注入的根本目的是为了初始化属性,使用属性的方法完成相应的功能
@Autowired 按照类型注入,如果存在两个相同Bean类型相同,则按照名称注入
@Autowired + @Qualifier("userDao") 按照类型注入的同时指定名称
@Resource(name="userDao") //@Resource 相当于@Autowired + @Qualifier
代码UserService.java

package com.imooc.demo1;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/*
* Spring的Bean管理的注解方式
* 传统方式需要在applicationContext.xml中配置<bean id="" class=""/>
*
*/
//@Component("userService")
@Service("userService")  //这里的名称,实际等效于bean id
public class UserService {

    @Value("米饭")
    private String something;

    @Autowired                //按照类型注入,如果存在两个相同Bean类型相同,则按照名称注入
    @Qualifier("userDao")     //单单用Qualifier注解没有注入userDao
    @Resource(name="userDao")   //@Resource 相当于@Autowired + @Qualifier

    private UserDao userDao;

    public String sayHello(String name){
        return "Hello"+name;
    }

    public void eat(){
        System.out.println("eat:" + something);
    }

    public void save(){
        System.out.println("service 保存用户方法。。。");
        userDao.save();
    }
}

(4)其他注解

@PostConstruct 相当于XML中的init-method
@PreDestroy相当于XML中的destroy-method,仅单例支持
@Scope("prototype")相当于XML中的scope

XML文件中的配置方式:

<bean id="man" class="com.imooc.ioc.demo3.Man" init-method="setup" destroy-method="teardown"/>   
<bean id="role" class="spring.chapter2.maryGame.Role" scope="prototype"/>

@PostConstruct @PreDestroy的使用方式:

package com.imooc.demo2;

import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component("bean1")
public class Bean1 {

    @PostConstruct
    public void init(){
        System.out.println("bean1 init 初始化方法。。。");
    }

    public void say(){
        System.out.println("bean1 say方法执行。。。");
    }

    @PreDestroy
    public void destroy(){
        System.out.println("bean1 destroy销毁方法。。。");
    }
}

@Scope("prototype")的使用方式,此时没有@PreDestroy

package com.imooc.demo2;


import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component("bean2")
@Scope("prototype")
public class Bean2 {

    @PostConstruct
    public void init(){
        System.out.println("bean2 init 初始化方法。。。");
    }

    public void say(){
        System.out.println("bean2 say方法执行。。。");
    }

    @PreDestroy
    public void destroy(){
        System.out.println("bean2 destroy销毁方法。。。");
    }

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容

  • 1.1 spring IoC容器和beans的简介 Spring 框架的最核心基础的功能是IoC(控制反转)容器,...
    simoscode阅读 6,685评论 2 22
  • 1.1 Spring IoC容器和bean简介 本章介绍了Spring Framework实现的控制反转(IoC)...
    起名真是难阅读 2,565评论 0 8
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,497评论 18 139
  • 文章作者:Tyan博客:noahsnail.com 3.4 Dependencies A typical ente...
    SnailTyan阅读 4,113评论 2 7
  • 羞松漏疏月 疏影香满枝 轻雾梦蝶,闲蝉惠风 印象溪谷,黄花白石 苍微长吟,山水清音 大山的回响 源远流长 黄河滔滔...
    企企阅读 112评论 1 3