Spring编程思想之SpringBean

一BeanDefinition 构建

public class BeanDefinitionCreationDemo {
    public static void main(String[] args) {
          //1.通过BeanDefinitionBuilder
                  //beanDefinitionBuilderToBuild();

        // 2. 通过 AbstractBeanDefinition 以及派生类

        creatBeanDefintionByGenericBeanDefinition();

    }

    private static void creatBeanDefintionByGenericBeanDefinition() {
        GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
        // 设置 Bean 类型
        genericBeanDefinition.setBeanClass(Person.class);
        MutablePropertyValues propertyValues = new MutablePropertyValues();

        propertyValues.add("id",123);
        propertyValues.add("name","zhansan");

        genericBeanDefinition.setPropertyValues(propertyValues);
    }

    private static void beanDefinitionBuilderToBuild() {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(Person.class);
        // 通过属性设置
        beanDefinitionBuilder.addPropertyValue("age",18);
        beanDefinitionBuilder.addPropertyValue("name","zhansan");

        BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        // BeanDefinition 并非 Bean 终态,可以自定义修改
        //后序补充
        beanDefinition.setDescription("没事意思" +
                "" +
                "");
        System.out.println(beanDefinition);
    }
}

二 命名SpringBean

2.1bean name 的生成

  • BeanNameGenerator

Strategy interface for generating bean names for bean definitions.

  • 实现类
    DefaultBeanNameGenerator
    当前类没有指定id 或者name时候自动生成id和name
    AnnotationBeanNameGenerator
 * {@link org.springframework.beans.factory.support.BeanNameGenerator}
 * implementation for bean classes annotated with the
 * {@link org.springframework.stereotype.Component @Component} annotation
 * or with another annotation that is itself annotated with
 * {@link org.springframework.stereotype.Component @Component} as a
 * meta-annotation. For example, Spring's stereotype annotations (such as
 * {@link org.springframework.stereotype.Repository @Repository}) are
 * themselves annotated with
 * {@link org.springframework.stereotype.Component @Component}.

三 别名的作用

四 如何注册BeanDefinition

4.1 BeanDefinition 注册

• XML 配置元信息
• <bean name=” ...” ... />

4.2 Java 注解配置元信息

• @Bean
• @Component
• @Import


    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(Config.class);

         context.refresh();
        Map<String, Config> beansOfType = context.getBeansOfType(Config.class);
        System.out.println("configBean"+beansOfType);
        System.out.println("1.命名 Bean 的注册方式"+context.getBean("userr"));
        context.close();

    }

    /*2. 通过@Compontent 方式*/
    @Component
    public  static  class  Config{
        /*一 @Bean的方式 注册Bean*/
        @Bean(name = {"user","xiaozi"})
        public  Person person(){
            return  new Person(){{

                setAge(999);
                setName("sanfeng");
            }};
        }
    }

4.3 Java API 配置元信息

• 命名方式: BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)
• 非命名方式:
BeanDefinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition,BeanDe
finitionRegistry)
• 配置类方式: AnnotatedBeanDefinitionReader#register(Class...)

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        context.refresh();
        // 通过 BeanDefinition 注册 API 实现
        // 1.命名 Bean 的注册方式
        registerUserBeanDefinition(context, "customerNameByAPI");
        // 2. 非命名 Bean 的注册方法
        registerUserBeanDefinition(context, "");

        System.out.println("获取所有UserBean"+context.getBeansOfType(Person.class));
        context.close();

    }
    /**
     *
     * @param registry
     * @param beanName
     */
    public  static  void  registerUserBeanDefinition(BeanDefinitionRegistry registry,String beanName ){
        BeanDefinitionBuilder beanDefinitionBuilder = genericBeanDefinition(Person.class);
        beanDefinitionBuilder.addPropertyValue("id",2l).addPropertyValue("name","zhansan")
        .addPropertyValue("age",18L);
        // 判断如果 beanName 参数存在时
        if (StringUtils.hasText(beanName)){
            registry.registerBeanDefinition(beanName,beanDefinitionBuilder.getBeanDefinition());
            //非命名 Bean 注册方法
        }else {
            BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(),registry);
        }
    }

    public static void registerUserBeanDefinition(BeanDefinitionRegistry registry) {
        registerUserBeanDefinition(registry, null);
    }

五 实例化Bean

Bean 实例化( Instantiation)

5.1 常规方式

• 通过构造器( 配置元信息: XML、 Java 注解和 Java API )
• 通过静态工厂方法( 配置元信息: XML 和 Java API )
• 通过 Bean 工厂方法( 配置元信息: XML和 Java API )
• 通过 FactoryBean( 配置元信息: XML、 Java 注解和 Java API )

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

   <!-- 静态工厂方法实例化 Bean -->
    <bean id="user-by-static-method" class="domain.Person" factory-method="createUser"/>

    <!-- Bean工厂方法方法实例化 Bean -->
    <bean id="user-by-instance-method" factory-bean="userFactory" />
    <bean id="userFactory" class="bean.factory.DefaultUserFactory"/>
<!--factoryBean 实例化方法-->
    <bean id="user-by-factory-bean"  class="bean.factory.UserFacotryBean"></bean>
</beans>

UserFactroy

    public class UserFacotryBean  implements FactoryBean {
        @Override
        public Object getObject() throws Exception {
            return Person.createUser();
        }

        @Override
        public Class<?> getObjectType() {
            return Person.class;
        }
    }

静态工程创建

    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
        // Make sure bean class is actually resolved at this point.
        Class<?> beanClass = resolveBeanClass(mbd, beanName);

        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
        }

        Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
        if (instanceSupplier != null) {
            return obtainFromSupplier(instanceSupplier, beanName);
        }
               // 如果是 实现factory-method="createUser"
        if (mbd.getFactoryMethodName() != null) {
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }
略略略

5.2 特殊方式

5.2.1通过 ServiceLoaderFactoryBean( 配置元信息: XML、 Java 注解和 Java API )

关键类ServiceLoader ServiceLoaderFactoryBean

  1. serviceLoad 用法

    public static void demoServiceLoader() {
        ServiceLoader<UserFactory> serviceLoader = ServiceLoader.load(UserFactory.class, Thread.currentThread().getContextClassLoader());
        displayServiceLoader(serviceLoader);
    }

    private static void displayServiceLoader(ServiceLoader<UserFactory> serviceLoader) {
        Iterator<UserFactory> iterator = serviceLoader.iterator();
        while (iterator.hasNext()) {
            UserFactory userFactory = iterator.next();
            System.out.println(userFactory.createUser());
        }
    }

2.Spring 管理Serviceloader

2.1. 定义/META-INF/special-bean-instantiation-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userFactoryServiceLoader" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
            <property name="serviceType"  value="bean.factory.UserFactory"></property>
    </bean>
</beans>

2.2使用spring管理serviceLoad


    private static void serviceLoadSrpingBean() {
        ApplicationContext beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/special-bean-instantiation-context.xml");
        ServiceLoader<UserFactory> serviceLoader = beanFactory.getBean("userFactoryServiceLoader", ServiceLoader.class);
        displayServiceLoader(serviceLoader);
    }

5.2.2通过 AutowireCapableBeanFactory#createBean(java.lang.Class, int, boolean)

• 通过 BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)

   // autowireCapableBeanFactory 实例化Bean
    private static void autowireCapableBeanFactory() {
        ApplicationContext beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/special-bean-instantiation-context.xml");
        AutowireCapableBeanFactory autowireCapableBeanFactory = beanFactory.getAutowireCapableBeanFactory();
        UserFactory userFactory=  autowireCapableBeanFactory.createBean(DefaultUserFactory.class);
        System.out.println(userFactory.createUser());
    }

六初始化SpringBean

Bean 初始化( Initialization)

6.1 @PostConstruct 标注方法

  • PostConctrust 是java提供的注解

6.2 实现 InitializingBean 接口的 afterPropertiesSet() 方法

6.3 自定义初始化方法

• XML 配置: <bean init-method=” init” ... />
• Java 注解: @Bean(initMethod=” init” )
• Java API: AbstractBeanDefinition#setInitMethodName(String)

6.4 代码Demo

/**
 * 默认 {@link UserFactory} 实现
 * Create by dgx 2021/9/5 22:48
 */
public class DefaultUserFactory implements UserFactory, InitializingBean  {

     //1. 基于@PostConstruct 注解  java原生注解

    @PostConstruct
    public  void init(){
        System.out.println("使用@PostConstruct  初始化UserFactory");
    }

    //2. 通过自定义初始化化方法
    public  void initUserFactory(){
        System.out.println("通过自动初始化化方法  初始化UserFactory");
    }
    // 3.实现 InitializingBean 注解
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("通过InitializingBean 初始化UserFactory");
    }
/**
 * 37 初始化Spring Bean
 * Create by dgx 2021/10/7 15:37
 */
@Configuration
public class BeanInitializationDemo {

    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 注册 Configuration Class(配置类)
        applicationContext.register(BeanInitializationDemo.class);
        // 启动 Spring 应用上下文
        applicationContext.refresh();
        // 非延迟初始化在 Spring 应用上下文启动完成后,被初始化
        System.out.println("Spring 应用上下文已启动...");
        // 依赖查找 UserFactory
        UserFactory userFactory = applicationContext.getBean(UserFactory.class);
        System.out.println(userFactory);
        System.out.println("Spring 应用上下文准备关闭...");
        // 关闭 Spring 应用上下文
        applicationContext.close();
        System.out.println("Spring 应用上下文已关闭...");
    }
     // Bean定义自顶注解方法名称
    @Bean(initMethod = "initUserFactory")
    @Lazy(value = false)
    public UserFactory userFactory() {
        return new DefaultUserFactory();
    }
}

6.4 源码执行时机

    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareMethods(beanName, bean);
                return null;
            }, getAccessControlContext());
        }
        else {
            invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
               // 此处执行  @PostConstruct方法
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
              // 此处执行 自定义的initMethod方法 和InitInitializingBean 接口方法
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    (mbd != null ? mbd.getResourceDescription() : null),
                    beanName, "Invocation of init method failed", ex);
        }
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }
    /**
     * Give a bean a chance to react now all its properties are set,
     * and a chance to know about its owning bean factory (this object).
     * This means checking whether the bean implements InitializingBean or defines
     * a custom init method, and invoking the necessary callback(s) if it does.
     * @param beanName the bean name in the factory (for debugging purposes)
     * @param bean the new bean instance we may need to initialize
     * @param mbd the merged bean definition that the bean was created with
     * (can also be {@code null}, if given an existing bean instance)
     * @throws Throwable if thrown by init methods or by the invocation process
     * @see #invokeCustomInitMethod
     */
    protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
            throws Throwable {

        boolean isInitializingBean = (bean instanceof InitializingBean);
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
            if (logger.isTraceEnabled()) {
                logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }
            if (System.getSecurityManager() != null) {
                try {
                    AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }, getAccessControlContext());
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }
            else {
                               //  实现了 InitializingBean
                ((InitializingBean) bean).afterPropertiesSet();
            }
        }
                                   // 自定义了BeanDefinition
        if (mbd != null && bean.getClass() != NullBean.class) {
            String initMethodName = mbd.getInitMethodName();
            if (StringUtils.hasLength(initMethodName) &&
                    !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                    !mbd.isExternallyManagedInitMethod(initMethodName)) {
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }

七 延迟初始化 和非延迟初始化的区别

区别是 延迟初始化化 是getBean的 适合处理初始化方法 非延迟初始化则是容器刷新完成之前

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

推荐阅读更多精彩内容