首页 > 编程语言 > 详细

spring

时间:2020-03-30 00:13:16      阅读:65      评论:0      收藏:0      [点我收藏+]

spring版本
bean的作用域
spring四种实例化bean的方式
关于bean别名
FactoryBean
bean循环依赖
BeanPostProcessor

spring版本

spring的发展:
第一阶段,spring1.x阶段所有的bean都是在xml中配置。
第二阶段,spring2.x阶段出现了基于注解的bean配置。
第三阶段,spring3.x阶段使用java配置类配置bean。
当前spring4.x阶段,推荐基于spring boot+java配置类。

返回顶部

bean的作用域

通过注解@Scope可以指定bean的作用域。bean有5种作用域:
1、Singleton单利:整个spring容器中只有一个实例 ,默认就是单利
2、protoType:每次调用新建一个实例。
3、request:在web应用中,每个请求创建一个实例
4、session:在web应用中,每个回话创建一个实例
5、globalSession:这个只在portal应用中存在。

返回顶部

spring四种实例化bean的方式

第一种:使用构造器实例化Bean。
这是最简单的方式,Spring IoC容器即能使用默认空构造器也能使用有参数构造器两种方式创建Bean。
技术分享图片
技术分享图片

第二种:使用静态工厂方式实例化Bean,使用这种方式除了指定必须的class属性,还要指定factory-method属性来指定实例化Bean的方法,而且使用静态工厂方法也允许指定方法参数,spring IoC容器将调用此属性指定的方法来获取Bean.
技术分享图片
技术分享图片

第三种:使用实例工厂方法实例化Bean,使用这种方式不能指定class属性,此时必须使用factory-bean属性来指定工厂Bean,factory-method属性指定实例化Bean的方法,而且使用实例工厂方法允许指定方法参数,方式和使用构造器方式一样。
技术分享图片

第四种:用 setter 方式.这种方式,只要写上对应的set、get方法,然后再bean.xml文件中利用property注入值即可。
技术分享图片

返回顶部

关于bean别名

每个 Bean 在 Spring 容器中都有一个唯一的名字(beanName)和 0 个或多个别名(aliases)。
我们从 Spring 容器中获取 Bean 的时候,可以根据 beanName,也可以通过别名。

beanFactory.getBean("beanName or alias");

在配置 的过程中,我们可以配置 id 和 name,看几个例子就知道是怎么回事了。

<bean id="messageService" name="m1, m2, m3" class="com.javadoop.example.MessageServiceImpl">

以上配置的结果就是:beanName 为 messageService,别名有 3 个,分别为 m1、m2、m3。

<bean name="m1, m2, m3" class="com.javadoop.example.MessageServiceImpl" />

以上配置的结果就是:beanName 为 m1,别名有 2 个,分别为 m2、m3。

<bean class="com.javadoop.example.MessageServiceImpl">

以上配置的结果就是beanName 为:com.javadoop.example.MessageServiceImpl#0,别名 1 个,为: com.javadoop.example.MessageServiceImpl

<bean id="messageService" class="com.javadoop.example.MessageServiceImpl">

以上配置的结果就是:beanName 为 messageService,没有别名。

返回顶部

FactoryBean

FactoryBean 适用于 Bean 的创建过程比较复杂的场景,比如数据库连接池的创建。
我们假设现在需要创建一个 Person 的 Bean,首先我们需要一个 Car 的实例,我们这里假设 Car 的实例创建很麻烦,那么我们可以把创建 Car 的复杂过程包装起来.

public class Person { 
    private Car car ;
    private void setCar(Car car){ this.car = car;  }  
}
public class MyCarFactoryBean implements FactoryBean<Car>{
    private String make; 
    private int year ;

    public void setMake(String m){ this.make =m ; }

    public void setYear(int y){ this.year = y; }

    public Car getObject(){ 
      // 这里我们假设 Car 的实例化过程非常复杂,反正就不是几行代码可以写完的那种
      CarBuilder cb = CarBuilder.car();

      if(year!=0) cb.setYear(this.year);
      if(StringUtils.hasText(this.make)) cb.setMake( this.make ); 
      return cb.factory(); 
    }

    public Class<Car> getObjectType() { return Car.class ; } 

    public boolean isSingleton() { return false; }
}
<bean class = "com.javadoop.MyCarFactoryBean" id = "car">
  <property name = "make" value ="Honda"/>
  <property name = "year" value ="1984"/>
</bean>
<bean class = "com.javadoop.Person" id = "josh">
  <property name = "car" ref = "car"/>
</bean>

在来看一个通过java config方式配置bean的例子。

@Configuration 
public class CarConfiguration { 

    @Bean 
    public MyCarFactoryBean carFactoryBean(){ 
      MyCarFactoryBean cfb = new MyCarFactoryBean();
      cfb.setMake("Honda");
      cfb.setYear(1984);
      return cfb;
    }

    @Bean
    public Person aPerson(){ 
    Person person = new Person();
      // 注意这里的不同
    person.setCar(carFactoryBean().getObject());
    return person; 
    } 
}

这个时候,其实我们的思路也很简单,把 MyCarFactoryBean 看成是一个简单的 Bean 就可以了,不必理会什么 FactoryBean,它是不是 FactoryBean 和我们没关系。

返回顶部

bean循环依赖

循环依赖

循环依赖其实就是循环引用,也就是两个或者两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。如下图:
技术分享图片
Spring中循环依赖场景有:
(1)构造器的循环依赖
(2)field属性的循环依赖
其中,构造器的循环依赖问题无法解决,只能拋出BeanCurrentlyInCreationException异常,在解决属性循环依赖时,spring采用的是提前暴露对象的方法。

构造器循环依赖:场景1

public class A{
   public A(B b){
   }
}

public class B{
   public B(A a){
   }
}

非构造器依赖:场景2

public class A{
  @Autowired
  B b;  

}

public class B{
  @Autowired
  A a;  

}

或者:场景3

public class A{
   public A(B b){
   }
}

public class B{
  @Autowired
  A a;  
}

ioc bean创建过程如下:
技术分享图片
createBeanInstance:实例化bean(执行的是构造器)。
populateBean:给bean初始化值(执行bean依赖的属性)

spring是通过三级缓存解决循环依赖:
singletonFactories(三级) : 单例对象工厂的cache
earlySingletonObjects (二级):提前暴光的单例对象的Cache (执行了构造器,但是未初始化)
singletonObjects(一级):单例对象的cache(一个完整的bean对象)

先分析以下非构造器循环依赖接是如何解决的:上面场景2的代码
1、实例化A,执行A的createBeanInstance,将A添加到三级缓存,然后执行A的populateBean方法,发现依赖B,从一、二、三级缓存中都没有B。
2、开始创建B,执行B的createBeanInstance,将B添加到三级缓存,然后执行B的populateBean方法,返现依赖A,从三级缓存中发现了A(虽然是不完整的A,但是也可以用于bean依赖),B的初始化完毕。
3、回到A继续,A可以拿到完整的B,流程结束。

方法createBeanInstance就是执行构造器的,所以只有构造器能成功执行对象才会被添加到三级缓存,而构造器依赖是在构造器中发生的依赖,对象还未被添加到三级缓存,所以构造器依赖无法解决。

spring构造器依赖抛异常是如何实现的呢?
Spring容器会将每一个正在创建的Bean 标识符放在一个“当前创建Bean池”中,Bean标识符在创建过程中将一直保持在这个池中,因此如果在创建Bean过程中发现自己已经在“当前创建Bean池”里时将抛出BeanCurrentlyInCreationException异常表示循环依赖;而对于创建完毕的Bean将从“当前创建Bean池”中清除掉。
Spring容器先创建单例A,A依赖B,然后将A放在“当前创建Bean池”中,此时创建B,B依赖C ,然后将B放在“当前创建Bean池”中,此时创建C,C又依赖A, 但是,此时A已经在池中,所以会报错,,因为在池中的Bean都是未初始化完的,所以会依赖错误 ,(初始化完的Bean会从池中移除)

源码

源码包含几个地方:
1、在createBeanInstance后设置三级缓存。
2、在populateBean初始化对象之前通过autowireByName循环调用getBean方法,从三级缓存中获取依赖对象。
具体代码位置https://github.com/sunyanhui123/note/issues/56#issue-422578341中都有注释说明。

返回顶部

BeanPostProcessor

名字叫做后置处理器,spring提供的扩展接口。
BeanPostProcessor接口作用是:如果我们需要在Spring容器完成Bean的实例化、配置和其他的初始化前后添加一些自己的逻辑处理,我们就可以定义一个或者多个BeanPostProcessor接口的实现,然后注册到容器中。
容器的每个Bean在调用初始化方法之前,都会获得该接口实现类的一个回调。容器调用接口定义的方法时会将该受管Bean的实例和名字通过参数传入方法,进过处理后通过方法的返回值返回给容器。

如何使用?
BeanPostProcessor接口有两个方法需要实现:postProcessBeforeInitialization和postProcessAfterInitialization。

@Configuration
    public class MyBeanPostProcessor implements BeanPostProcessor {

        public MyBeanPostProcessor() {
            super();
            System.out.println("这是BeanPostProcessor实现类构造器!!");
        }

        @Override
        public Object postProcessAfterInitialization(Object bean, String arg1)
                throws BeansException {
            System.out.println("bean处理器:bean创建之后..");
            return bean;
        }

        @Override
        public Object postProcessBeforeInitialization(Object bean, String arg1)
                throws BeansException {
            System.out.println("bean处理器:bean创建之前..");

            return bean;
        }
    } 

要使用BeanPostProcessor回调,就必须先在容器中注册实现该接口的类,那么如何注册呢?BeanFactory和ApplicationContext容器的注册方式不大一样:若使用BeanFactory,则必须要显示的调用其addBeanPostProcessor()方法进行注册,参数为BeanPostProcessor实现类的实例;如果是使用ApplicationContext,那么容器会在配置文件在中自动寻找实现了BeanPostProcessor接口的Bean,然后自动注册,我们要做的只是配置一个BeanPostProcessor实现类的Bean就可以了。

ApplicationContext容器注册BeanPostProcessor

入口:refresh方法中的registerBeanPostProcessors方法。

 protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
    }
    public static void registerBeanPostProcessors(
            ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
        /**
         *1.代码走到了这里的时候其实 BeanDefinition数据已经被加载了,只是bean还没有被实例化
         所以这个是去容器里面找到所有类型为BeanPostProcessor的beanName
         */
        String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

        //记录所有的beanProcessor数量,在这之前也可能注册了一部分Spring内部的BeanPostProcessors接口,例如:ApplicationContextAwareProcessor
        int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
        //貌似只是记录日志用的
        beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

        // 优先级最高的BeanPostProcessors,这类最先调用;需要实现PriorityOrdered接口
        List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
        //内部BeanPostProcessors
        List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
        //继承了Ordered接口,优先级比上面低一点
        List<String> orderedPostProcessorNames = new ArrayList<String>();
        //这就是普通的了,优先级最低
        List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
        //下面的这些代码就是遍历所有postProcessorNames,按优先级排序;类型PriorityOrdered>Ordered>普通;在这个类型基础上,还要对他们的order属性就行排序;
        for (String ppName : postProcessorNames) {
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
                priorityOrderedPostProcessors.add(pp);
                if (pp instanceof MergedBeanDefinitionPostProcessor) {
                    internalPostProcessors.add(pp);
                }
            }
            else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
                orderedPostProcessorNames.add(ppName);
            }
            else {
                nonOrderedPostProcessorNames.add(ppName);
            }
        }

        // First, register the BeanPostProcessors that implement PriorityOrdered.
        sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
        registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);//入口

        // Next, register the BeanPostProcessors that implement Ordered.
        List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
        for (String ppName : orderedPostProcessorNames) {
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            orderedPostProcessors.add(pp);
            if (pp instanceof MergedBeanDefinitionPostProcessor) {
                internalPostProcessors.add(pp);
            }
        }
        sortPostProcessors(beanFactory, orderedPostProcessors);
        registerBeanPostProcessors(beanFactory, orderedPostProcessors);//入口

        // Now, register all regular BeanPostProcessors.
        List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
        for (String ppName : nonOrderedPostProcessorNames) {
            //这里要注意一下了,看到没有,这个时候已经调用了getBean来生成实例对象了;
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            nonOrderedPostProcessors.add(pp);
            if (pp instanceof MergedBeanDefinitionPostProcessor) {
                internalPostProcessors.add(pp);
            }
        }
        registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);//入口

        // 排序
        sortPostProcessors(beanFactory, internalPostProcessors);
        //注册
        registerBeanPostProcessors(beanFactory, internalPostProcessors);//入口

        // 加入ApplicationListenerDetector
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
    }

    /**
     * 注册 BeanPostProcessor beans.
     * 容器中beanPostProcessors是一个ArrayList来持有这些BeanPostProcessors
     */
    private static void registerBeanPostProcessors(
            ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
        for (BeanPostProcessor postProcessor : postProcessors) {
            beanFactory.addBeanPostProcessor(postProcessor);
        }
    }
    @Override
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
        this.beanPostProcessors.remove(beanPostProcessor);
        this.beanPostProcessors.add(beanPostProcessor);
        //将是否 hasInstantiationAwareBeanPostProcessors设置为true
        if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
            this.hasInstantiationAwareBeanPostProcessors = true;
        }
        if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
            this.hasDestructionAwareBeanPostProcessors = true;
        }
    }

总结一下上面流程:
1、Spring加载完了所有的BeanDefinition之后,找到所有类型为BeanPostProcessors的BeanDefinition对象;
2、根据得到的类型是否实现了PriorityOrdered>Ordered>无继承Ordered;在这个优先级基础上,每个实现了Ordered接口的(PriorityOrdered也实现了Ordered)都有一个order属性,还要根据order来进行排序。
3、将BeanPostProcessors实例都添加到BeanFactory中。

到此所有的后置处理器都已经添加到容器中了,那么具体是在什么地方使用的呢?
调用的地方比较多,还有很多Spring内部的接口,还有其他的比如MergedBeanDefinitionPostProcessor等也继承了BeanPostProcessors接口的扩展接口,
我们这里先只分析我们自己继承这个BeanPostProcessors接口的实例是什么时候被调用的;
答案是initializeBean方法。
回顾一下bean创建过程的三个重要方法:
1、createBeanInstance:实例化bean
2、populateBean :给bean设置值(包括依赖注入的bean)
3、initializeBean:各种回调
第三个方法负责回调就是执行BeanPostProcessors的地方。

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
        //省略....
        if (mbd == null || !mbd.isSynthetic()) {
            //初始化之前
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {//初始化
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        //初始化之后
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
        //省略...
    }
//注意 每一个实例对象触发这个的时候 都是执行所有的BeanPostProcessors实例对象
        @Override
        public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

            Object result = existingBean;
            for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
                //这里是循环
                //	result =BeanPostProcessor调用执行方法;返回的对象还是result,
                //	只是有可能被某个BeanPostProcessor加强了
                //	beanProcessor.postProcessAfterInitialization(result, beanName);
                if (result == null) {
                    return result;
                }
            }
            return result;
        }

所以只要调用getBean方法,就会执行BeanPostProcessors。

返回顶部

spring

原文:https://www.cnblogs.com/yanhui007/p/12595474.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!