SpringBean

概述

控制反转:一种通过描述(在Java中可以是xml或者注解),通过第三方产生或获取特定对象的方式。由程序中通过主动new的方式创建对象,到由Spring管理对象的创建和销毁;
依赖注入:生成的对象需要的成员属性通过在xml或者注解的形式给Bean配置注入。

BeanFactory接口

Spring Ioc容器的设计主要基于BeanFactory和ApplicationContext两个接口,其中ApplicationContext是BeanFactory的子接口之一,BeanFactory提供了SpringIoc最底层的设计。

public interface BeanFactory {
	String FACTORY_BEAN_PREFIX = "&";
	//返回给定名称注册的bean实例。根据bean的配置情况,如果是singleton模式将返回一个共享实例,否则将返回一个新建的实例,如果没有找到指定bean,该方法可能会抛出异常
	Object getBean(String name) throws BeansException;
	//通过Bean的名字匹配,并转换为给定class类型,可以是接口或父类型
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;
	//返回指定类型的bean实例
	<T> T getBean(Class<T> requiredType) throws BeansException;
	
	Object getBean(String name, Object... args) throws BeansException;
	//判断工厂中是否包含给定名称的bean定义,若有则返回true
	boolean containsBean(String name);
	//判断给定名称的bean定义是否为单例模式,默认情况下是单例模式
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
	//这个bean是否总是提供独立的实例
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
	//通过Bean的名字匹配到的Bean的类型是否是指定的类型
	boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;
	//返回给定名称的bean的Class
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;
	//返回给定bean名称的所有别名 
	String[] getAliases(String name);
}

如果当前的工厂没有发现Bean实例,那么会去查找父类工厂。当前工厂中的Bean实例支持覆盖父类工厂中相同名字的Bean实例。
Spring的依赖注入就是通过实现beanFactory。
BeanFactory的官方解释:

		 ...一堆废话
         In contrast to the methods in {@link ListableBeanFactory}, all of the
         operations in this interface will also check parent factories if this is a
         {@link HierarchicalBeanFactory}. If a bean is not found in this factory instance,
         the immediate parent factory will be asked. Beans in this factory instance
         are supposed to override beans of the same name in any parent factory.
        
         Bean factory implementations should support the standard bean lifecycle interfaces
         as far as possible. The full set of initialization methods and their standard order is:
         
  		 BeanNameAware's {@code setBeanName}
         BeanClassLoaderAware's {@code setBeanClassLoader}
         BeanFactoryAware's {@code setBeanFactory}
         EnvironmentAware's {@code setEnvironment}
         EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
         ResourceLoaderAware's {@code setResourceLoader}
         (only applicable when running in an application context)
         ApplicationEventPublisherAware's {@code setApplicationEventPublisher}
         (only applicable when running in an application context)
         MessageSourceAware's {@code setMessageSource}
         (only applicable when running in an application context)
         ApplicationContextAware's {@code setApplicationContext}
         (only applicable when running in an application context)
         ServletContextAware's {@code setServletContext}
         (only applicable when running in a web application context)
         {@code postProcessBeforeInitialization} methods of BeanPostProcessors
         InitializingBean's {@code afterPropertiesSet}
         a custom init-method definition
         {@code postProcessAfterInitialization} methods of BeanPostProcessors
         
        
         On shutdown of a bean factory, the following lifecycle methods apply:
         
 		 {@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors
         DisposableBean's {@code destroy}
         a custom destroy-method definition

Bean的作用域

Spring提供了4种作用域,它会根据情况决定是否生成新的对象。
单例(singleton):它是默认选项,整个应用中Spring只生成一个Bean的实例;
原型(prototype):每次注入或者通过SpringIoc容器获取Bean时,Spring都会为它创建一个新实例;
会话(session) :一个Session中,Spring只会创建一个实例;
请求(request) :一次请求中Spring会创建一个实例,不同的请求会创建不同的实例。

SpringBean的生命周期

在这里插入图片描述

Demo

/**
 * 针对每一个springIOC容器中的bean,它自己不会执行这两个方法
 */
public class BeanPostProcessorImpl implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("【" + bean.getClass().getSimpleName() + "】对象" + beanName + "开始实例化");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("【" + bean.getClass().getSimpleName() + "】对象" + beanName + "实例化完成");
        return bean;
    }
}
/**
 * 针对Spring Ioc容器
 */
public class DisposableBeanImpl implements DisposableBean {
    @Override
    public void destroy() throws Exception {
        System.out.println("调用DisposableBean的destroy方法");
    }
}
public class JuiceMake implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean {
    public JuiceMake(){
        System.out.println("无参构造函数");
    }

    public JuiceMake(String s){
        System.out.println("有参构造函数");
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("【" + this.getClass().getSimpleName() + "】调用BeanNameAware接口的setBeanName方法");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("【" + this.getClass().getSimpleName() + "】调用BeanFactoryAware接口的setBeanFactory方法");
    }

    //要求springIoc容器实现ApplicationCoontext接口
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("【" + this.getClass().getSimpleName() + "】调用ApplicationContextAware接口的setApplicationContext方法");
    }
	
    //BeanPostProcessor的postProcessBeforeInitialization方法
	
	@PostConstruct
	public void postConstruct() {
        System.out.println("postConstruct");
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("【" + this.getClass().getSimpleName() + "】调用InitializingBean接口的afterPropertiesSet方法");
    }

    //自定义初始化方法
    public void init() {
        System.out.println("【" + this.getClass().getSimpleName() + "】执行自定义初始化方法");
    }

    //BeanPostProcessor的postProcessAfterInitialization方法
	
	//使用这个Bean

	@PreDestroy
	public void preDestroy() {
        System.out.println("preDestroy");
    }
 
    //DisposableBean的destroy方法

    //自定义销毁方法
    public void destroy() {
        System.out.println("【" + this.getClass().getSimpleName() + "】执行自定义销毁方法");
    }

    private String beverageShop = null;
    private Source source = null;

    public String getBeverageShop() {
        return beverageShop;
    }

    public void setBeverageShop(String beverageShop) {
        System.out.println("设置属性beverageShop");
        this.beverageShop = beverageShop;
    }

    public Source getSource() {
        return source;
    }

    public void setSource(Source source) {
        System.out.println("设置属性source");
        this.source = source;
    }

    public String makeJuice() {
        String juice = "这是一杯由" + beverageShop + "饮品店,提供的" + source.getSize() + source.getSugar() + source.getFruit();
        return juice;
    }
}
	<bean id="beanPostProcessor" class="spring.springIOC.BeanPostProcessorImpl"/>
    <bean id="disposableBean" class="spring.springIOC.DisposableBeanImpl"/>
    <!--Spring扫描Source类之后也可以用注解注入属性(@Autowired,@Resource)-->
    <bean id="source" class="spring.springIOC.Source">
        <property name="fruit" value="橙汁"/>
        <property name="sugar" value="少糖"/>
        <property name="size" value="大杯"/>
    </bean>
    <!--init方法执行前先设置属性-->
    <!--实例化时执行默认的无参构造函数,修饰符无影响-->
    <bean id="juiceMake" class="spring.springIOC.JuiceMake" init-method="init" destroy-method="destroy" >
        <property name="source" ref="source"/>
        <property name="beverageShop" value="贡茶"/>
    </bean>
public class IocMain {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:config-iocSpring.xml");
        JuiceMake juiceMake = ctx.getBean("juiceMake",JuiceMake.class);
        System.out.println(juiceMake.makeJuice());
        ctx.close();
    }
}
//output:
【DisposableBeanImpl】对象disposableBean开始实例化
【DisposableBeanImpl】对象disposableBean实例化完成
【Source】对象source开始实例化
【Source】对象source实例化完成
无参构造函数
设置属性source
设置属性beverageShop
【JuiceMake】调用BeanNameAware接口的setBeanName方法
【JuiceMake】调用BeanFactoryAware接口的setBeanFactory方法
【JuiceMake】调用ApplicationContextAware接口的setApplicationContext方法
【JuiceMake】对象juiceMake开始实例化
 postConstruct
【JuiceMake】调用InitializingBean接口的afterPropertiesSet方法
【JuiceMake】执行自定义初始化方法
【JuiceMake】对象juiceMake实例化完成
这是一杯由贡茶饮品店,提供的大杯少糖橙汁
五月 21, 2019 10:58:17 上午 org.springframework.context.support.AbstractApplicationContext doClose
 preDestroy
【JuiceMake】执行自定义销毁方法
调用DisposableBean的destroy方法

源码路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean

当配置了多个BeanPostProcessor接口的实现类时,有顺序影响。
源码路径:org.springframework.context.support.PostProcessorRegistrationDelegate.registerBeanPostProcessors
PriorityOrdered>Ordered>None。
不同接口实现时,高优先级的BeanPostProcessor实现类会作用于低优先级的初始化过程。
int getOrder();方法的返回值越大,优先级越低。

依赖注入的三种方式

Spring通过反射技术实现。Spring的依赖注入就是通过实现beanFactory
挺详细的:https://www.cnblogs.com/xiaoxi/p/5865330.html

通过注解装配Bean

https://blog.csdn.net/u013412772/article/details/73741710

@Component只能注解在类上,只能将类作为一个Bean。@Bean是一个方法级别上的注解,会将方法的返回对象作为Spring的Bean,存放在Ioc容器中,主要用在@Configuration注解的类里,也可以用在@Component注解的类里。

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
	//一个字符串数组,允许配置多个BeanName,默认情况下Bean的名字和方法名相同,设置name属性可以指定名字,也可以取别名
	String[] name() default {};
	//属性被注入的方式,by name or by type,default no
	Autowire autowire() default Autowire.NO;
	//自定义初始化方法
	String initMethod() default "";
	//自定义销毁方法
	String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}

Demo

@Configuration		//相当于xml配置的<beans></beans>
public class ConfigBean {
    @Resource	//先根据属性名匹配,如果找不到再按类型匹配;如果设置了name属性,那就只会按照名字查找.
    private Source source;

    @Bean(initMethod = "init2")
    public JuiceMake juiceMake2(){
        JuiceMake juiceMake2 = new JuiceMake();
        juiceMake2.setBeverageShop("贡茶");
        juiceMake2.setSource(source);
        return juiceMake2;
    }
    
    //也可以在内部使用@Configuration,它会自动装配,不需要使用@Import(xxConfiguration.class)
	@Configuration
    static class InnerStaticClass {
        @Bean
        Source getSource() {
            Source source = new Source();
            source.setFruit("椰汁");
            return source;
        }
    }
}

可以使用AnnotationConfigApplicationContext上下文加载,例如:

ApplicationContext context = new AnnotationConfigApplicationContext(ConfigBean.class);  //扫描加载@Configuration的文件
Object object = context.getBean("configBean.InnerStaticClass");//获取内部类的Bean

但这时需要注意Spring只加载了ConfigBean,其中的Source属性并不在Spring容器中,因此Source属性的依赖注入(DI)会失效,可以这样解决:在ConfigBean上加上一个注解@ImportResource(location = {"classpath:config-iocSpring.xml"}),这样xml里定义的Bean就会被加载进来。

细节

  1. 定义相同id的Bean
    实体:
public class Hello {
    private String name;
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

main.xml:

<bean id="hello" class="springBean.Hello">
        <property name="name" value="ljh"/>
    </bean>
    <import resource="follow.xml"/>

follow.xml:

<bean id="hello" class="springBean.Hello">
        <property name="name" value="lyf"/>
    </bean>

测试类:

public class Test {
    public static void main(String[] arsg) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:main.xml");
        Hello hello = (Hello) context.getBean("hello");
        System.out.println(hello.getName());
    }
}
//output:
lyf

相同id的bean不允许在一个xml配置文件中配置,但是可以在不同文件中配置,即便存在父子关系。从输出结果可以看出,后定义的Bean会覆盖之前定义的。这是因为spring ioc容器在加载bean的过程中,类DefaultListableBeanFactory会对id相同的bean进行处理:后加载的配置文件的bean,覆盖先加载的配置文件的bean。DefaultListableBeanFactory类中,有个属性allowBeanDefinitionOverriding,默认值为true,该值就是用来指定出现两个bean的id相同的情况下,如何进行处理。如果该值为false,则不会进行覆盖,而是抛出异常。
2.类上加了@Component注解,同时又在配置文件中配置了Bean,如果设置的id不同,那么Spring容器会产生两个相同类型的Bean;如果设置的id相同,那么在XML中配置的Bean会覆盖通过注解配置的Bean。
3.通过XML配置Bean的属性时,可以搭配@Autowired等注解一起配置,<property />和注解可以一起用。
4.一个属性使用注解和XML同时配置,优先XML配置。
5.通过XML的方式可以设置Bean的静态属性,但是通过@Autowired注解的形式不行。XML里设置属性可以调用静态的setNameXX方法。
6.XML里配置的属性引用可以是通过注解配置生成的Bean。

@Component
public class A {}

public class C {
	private static A a;
	public void setA(A a) {
		C.a = a;
	}
}

<bean id = "b" class = "C">
	<property name = "a" ref = "a"/>
</bean>

参考书籍:JavaEE互联网轻量级框架整合开发

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值