zoukankan      html  css  js  c++  java
  • 【一步一步学习spring】spring bean管理(上)

    1. spring 工厂类

    我们前边的demo中用到的spring 工厂类是ClassPathXmlApplicationContext,从上图可以看到他还有一个兄弟类FileSystemApplicationContext,这个类是加载非classpath路径下的配置文件,本质是一样的。

    从继承关系图中可以看到我们经常看到的ApplicationContext,这个是新版本才引入的工厂类接口。在旧版本中是BeanFactory,是在旧版本的基础上增加了几个新功能,如国际化,resourceLoader等。还有一个区别就是加载bean的时机的区别,Beanfactory是在使用bean的时候创建的;ApplicationContext是在加载配置文件的时候就将所有非懒加载的单例创建出来了。

    @Test
    /**
    * 使用beanFactory加载bean
    */
    public void demo3() {
        // 老方式的工厂类,需要自己创建Resource对象进行加载。
        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("application-context.xml"));
        // 通过工厂获取类对象
        UserService userService = (UserService) beanFactory.getBean("userService");
        userService.sayHello();
    }
    

    2. spring bean管理

    2.1 三种实例化Bean的方式

    • 使用类构造器实例化(默认无参数)
    • 使用静态工厂方法实例化(简单工厂模式)
    • 使用实例工厂模式实例化(工厂方法模式)

    一般情况都是用第一种方式,只有类的构造非常复杂的情况下才会用后边的俩种。

    2.1.1 使用类构造器实例化

    • bean
    package com.ioc.demo2;
    
    /**
     * Bean实例化的三种方式:采用无参的构造方法的方式
     */
    public class Bean1 {
    	public Bean1() {
    		System.out.println("Bean1 被实例化了。");
    	}
    }
    
    • xml
    <!-- 无参数构造方法构建 -->
    <bean id="bean1" class="com.ioc.demo2.Bean1"></bean>
    
    • 调用
    @Test
    public void demo1() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-context.xml");
        Bean1 bean = (Bean1) applicationContext.getBean("bean1");
    }
    

    2.1.2 静态工厂方法实例化

    • bean
    /**
     * Bean的实例化三种方式:静态工厂实例化方式
     */
    public class Bean2 {
    }
    
    • beanFactory
    /**
     * Bean2的静态工厂
     */
    public class Bean2Factory {
    	
    	public static Bean2 createBean2() {
    		System.out.println("Bean2Factory 执行了。");
    		return new Bean2();
    	}
    }
    
    • xml
    <!-- 静态工厂的方式 -->
    <bean id="bean2" class="com.ioc.demo2.Bean2Factory" factory-method="createBean2"></bean>
    
    • 调用
    @Test
    public void demo2() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-context.xml");
        Bean2 bean = (Bean2) applicationContext.getBean("bean2");
    }
    

    2.1.3 使用实例工厂模式实例化

    • bean
    /**
     * 使用实例工厂模式实例化
     */
    public class Bean3 {
    }
    
    • beanFactory
    /**
     * Bean3的实例工厂
     */
    public class Bean3Factory {
    	public Bean3 createBean3() {
    		System.out.println("Bean3Factory 被调用了。");
    		return new Bean3();
    	}
    }
    
    • xml
    <!-- 实例工厂的方式 -->
    <bean id="bean3Factory" class="com.ioc.demo2.Bean3Factory"></bean>
    <bean id="bean3" factory-bean="bean3Factory" factory-method="createBean3"></bean>
    
    • 调用
    @Test
    public void demo3() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-context.xml");
        Bean3 bean = (Bean3) applicationContext.getBean("bean3");
    }
    

    2.2 bean的常用配置

    2.2.1 id和name

    • 一般情况下,装配一个Bean时,通过指定一个id属性作为Bean的名称
    • id属性在IOC容器中是唯一的
    • name其实也要是唯一的,同id的区别是可以存在特殊字符。这个应该是有历史原因的,不再赘述。

    2.2.2 class

    • 设置一个类的全路径的名称,主要作用是IOC容器生成类的实例

    2.2.3 scope

    类别 说明
    singleton(默认) 在SpringIOC容器中仅存在一个Bean实例,Bean以单实例的方式存在
    prototype 每次调用getBean()时都会返回一个新的实例
    request 每个HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
    session 同一个HTTP session共享一个Bean,不同的HTTP session使用不同的Bean。该作用域仅适用于WebApplicationContext环境

    2.3 spring容器中Bean的生命周期

    spring初始化bean或销毁bean时,有时候需要做一些处理工作,因此spring可以在创建和销毁bean的时候调用bean的声明周期方法。

    <bean id="xxx" class="...Yoo" init-method="init" destory-method="destory" />
    

    当bean在被载入到容器中时会调用init;当bean从容器中删除的时候调用destroy(scope=singleton有效)

    2.3.1 instantiate bean对象实例化

    即调用类的构造方法。

    2.3.2 populate properties封装属性

    即调用类的属性设置方法。

    2.3.3 如果Bean实现BeanNameAware,则执行setBeanName

    即为该bean设置name的时候调用,可以想象为容器为map,name就是那个key。

    2.3.4 如果Bean实现BeanFactoryAware或者ApplicationContextAware设置工厂,则执行setBeanFactory或者上下文对象setApplicationContext

    即为该bean设置容器的时候调用。

    2.3.5 如果存在类实现BeanPostProcessor(后处理Bean),执行postProcessBeforeInitialization

    即在调用init-method之前调用。

    2.3.6 如果bean实现InitializingBean,则实行afterPropertiesSet

    属性设置后调用。

    2.3.7 调用<bean init-method="init">指定的初始化方法

    执行init方法。

    2.3.8 如果存在类实现BeanPostProcessor(后处理Bean),执行postProcessAfterInitialization

    即在调用init-method之后调用。

    2.3.9 执行业务处理

    即调用bean中的业务方法。

    2.3.10 如果Bean实现DisposableBean,执行destory方法

    spring自身中的销毁方法。

    2.3.11调用<bean destory-method="teardown">指定的销毁方法

    执行teardown方法。

    2.3.12 相关代码

    • bean
    package com.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 Bean implements BeanNameAware, ApplicationContextAware, InitializingBean, DisposableBean{
    	private String name;
    	public Bean() {
    		System.out.println("第一步:构造方法");
    	}
    	public void setName(String name) {
    		System.out.println("第二步:设置属性");
    		this.name = name;
    	}
    	public void setBeanName(String name) {
    		System.out.println("第三步:设置bean的名称:" + name);
    	}
    	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    		System.out.println("第四步:设置bean工厂");
    	}
    	public void afterPropertiesSet() throws Exception {
    		System.out.println("第六步:属性设置后");
    	}
    	public void init() {
    		System.out.println("第七步:初始化方法");
    	}
    	public void run() {
    		System.out.println("第九步:业务代码");
    	}
    	public void destroy() throws Exception {
    		System.out.println("第十步:spring自身的销毁");
    	}
    	public void teardown() {
    		System.out.println("第十一步:销毁方法");
    	}
    }
    
    • MyBeanPostProcessor
    package com.ioc.demo3;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    
    public class MyBeanPostProcessor implements BeanPostProcessor {
    
        // 可以用beanName对要生效的bean做过滤操作
    	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("第四步:bean初始化前");
    		return bean;
    	}
    
    	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("第八步:bean初始化后方法");
    		return bean;
    	}
    
    }
    
    • xml
    <!-- Bean的声明周期============================================ -->
    <bean id="bean" class="com.ioc.demo3.Bean" init-method="init" destroy-method="teardown">
        <property name="name" value="xxx"></property>
    </bean>
    <!-- 注意这个配置是对所有的bean都生效的 -->
    <bean class="com.ioc.demo3.MyBeanPostProcessor"></bean>
    
    • 调用
    package com.ioc.demo3;
    
    import org.junit.Test;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class SpringDemo3 {
    	
    	@Test
    	public void demo1() {
            // ApplicationContext接口没有close方法,故直接使用了其实现类
    		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
    		Bean bean = (Bean)context.getBean("bean");
    		bean.run();
    		context.close();
    	}
    }
    
    • 执行结果
    第一步:构造方法
    第二步:设置属性
    第三步:设置bean的名称:bean
    第四步:设置bean工厂
    第四步:bean初始化前
    第六步:属性设置后
    第七步:初始化方法
    第八步:bean初始化后方法
    第九步:业务代码
    第十步:spring自身的销毁
    第十一步:销毁方法
    

    2.3.13 使用声明周期中的BeanPostProcessor增强类中的方法

    这个本质上是可以对类中的方法做动态代理,为后边的AOP做铺垫。

    下边举个栗子:在delete方法前面加一个鉴权的功能,不更改具体的类方法

    • 接口类
    package com.ioc.demo3;
    
    public interface BeanDao {
    	
    	public void find();
    	public void add();
    	public void delete();
    	public void update();
    
    }
    
    • 接口实现类
    package com.ioc.demo3;
    
    public class BeanDaoImpl implements BeanDao {
    
    	public void find() {
    		System.out.println("查询");
    	}
    
    	public void add() {
    		System.out.println("添加");
    	}
    
    	public void delete() {
    		System.out.println("删除");
    	}
    
    	public void update() {
    		System.out.println("更新");
    	}
    
    }
    
    
    • BeanPostProcessor
    package com.ioc.demo3;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    
    public class MyBeanPostProcessor implements BeanPostProcessor {
    
    	public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
    		System.out.println("第四步:bean初始化前");
    		return bean;
    	}
    
    	public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
    		System.out.println("第八步:bean初始化后方法");
    		if (beanName.equals("beanDao")) {
    			Object proxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
    				
    				public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    					if (method.getName().equals("delete")) {
    						System.out.println("鉴权是否是root用户");
    						return method.invoke(bean, args);
    					}
    					return method.invoke(bean, args);
    				}
    			});
    			return proxy;
    		}
    		return bean;
    	}
    
    }
    
    • xml
    <bean class="com.ioc.demo3.MyBeanPostProcessor"></bean>
    <bean id="beanDao" class="com.ioc.demo3.BeanDaoImpl"></bean>
    
    • 调用
    package com.ioc.demo3;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class SpringDemo3 {
    	
    	@Test
    	public void demo1() {
    		ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
    		BeanDao beanDao = (BeanDao)context.getBean("beanDao");
    		beanDao.add();
    		beanDao.delete();
    		beanDao.find();
    		beanDao.update();
    	}
    }
    
  • 相关阅读:
    【css】rem及其替换方案
    【css】如何实现环形进度条
    【js】我们需要无限滚动列表吗?
    【js】再谈移动端的模态框实现
    【js】callback时代的变更
    【js】为什么要使用react+redux
    【js】JavaScript parser实现浅析
    【css】回想下经典的布局
    【JS】温故知新: 从parseInt开始
    【渲染原理】浏览器渲染原理的个人整理
  • 原文地址:https://www.cnblogs.com/xxxuwentao/p/9587969.html
Copyright © 2011-2022 走看看