4、屬性賦值和自動裝配

一、屬性賦值

  • 屬性賦值相關的注解

@Value
@PropertySource
springboot中的@ConfigurationProperties(prefix = "xxx")

二、自動裝配

  • 概念:Spring利用依賴注入(DI),完成對IOC容器中中各個組件的依賴關系賦值

1、@Autowired:自動注入

1)、默認優先按照類型去容器中找對應的組件:applicationContext.getBean(BookDao.class);找到就賦值
2)、如果找到多個相同類型的組件,再將屬性的名稱作為組件的id去容器中查找applicationContext.getBean("bookDao")
3)、@Qualifier("bookDao"):使用@Qualifier指定需要裝配的組件的id,而不是使用屬性名
4)、自動裝配默認一定要將屬性賦值好,沒有就會報錯;可以使用@Autowired(required=false);
5)、@Primary:讓Spring進行自動裝配的時候,默認使用首選的bean;也可以繼續使用@Qualifier指定需要裝配的bean的名字

2、@Resource(JSR250)和@Inject(JSR330)[java規范的注解]

1、@Resource:可以和@Autowired一樣實現自動裝配功能;默認是按照組件名稱進行裝配的;沒有能支持@Primary功能。
2、@Inject:需要導入javax.inject的包,和Autowired的功能一樣。沒有required=false的功能;

總結:

  • @Autowired:Spring定義的; @Resource、@Inject都是java規范
  • AutowiredAnnotationBeanPostProcessor解析完成自動裝配功能

三、自定義組件想要使用Spring容器底層的一些組件

  • 例如:ApplicationContext,BeanFactory,xxx

1、Aware接口

  • Aware是一個具有標識作用的超級接口,實現該接口的bean是具有被spring 容器通知的能力的,而被通知的方式就是通過回調??傊褐苯踊蜷g接實現了這個接口的類,都具有被spring容器通知的能力。
  • 繼承接口:


    Aware接口繼承接口
  • 可以知道這些xxxAware接口都只有一個setxxx方法,目的就是給實現該接口的類的xxx屬性設置值。在spring中這些實現xxxAware接口的類是如何實現感應并設置xxx屬性的值的呢,答案就是在spring容器中在工廠類創建實例后使用instanceof判斷實例是否屬于xxxAware接口的實例,如果結果是true的話,那么spring容器類就會調用實例的setXxx()方法給實例的xxx屬性設置值。簡單來說就是實現這些 Aware接口的Bean在被初始之后,可以從Spring容器中取得一些相對應的資源,例如實現BeanFactoryAware接口的Bean在初始后,Spring容器將會注入BeanFactory的實例,而實現ApplicationContextAware接口的Bean,在Bean被初始后,將會被注入 ApplicationContext的實例等等。
  • 注意:

有六大類xxxAware是由spring容器自動注冊在容器中的,應用程序不需要再次的在容器中注入了,但是如果我們實現其他的xxxAware,還必須在容器中注入才能使用,從ApplicationContextAwareProcessor源碼可以解讀出,這六類特殊的xxxAware是:

  • @see org.springframework.context.EnvironmentAware
  • @see org.springframework.context.EmbeddedValueResolverAware
  • @see org.springframework.context.ResourceLoaderAware
  • @see org.springframework.context.ApplicationEventPublisherAware
  • @see org.springframework.context.MessageSourceAware
  • @see org.springframework.context.ApplicationContextAware

2、從實現到原理再到實現

  • 前面可知實現xxxAware接口主要是為了獲取spring的一些特性
    (1)自己實現一個接口獲取spring的特性,比如BeanFactoryAware
public class Animal implements BeanFactoryAware {
    private BeanFactory beanFactory;
 
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
}
  • 注意:我們的Animal 類實現了aware接口,如果我們直接在應用中new一個Animal 的對象,當然是拿不到beanFactory變量的,我們必須在spring的配置文件中聲明我們的fruit對象才行,也就是說Animal 對象必須交給容器進行管理,容器幫你把各種aware接口中想要注入的對象設置到bean中。具體看容器管理aware接口的代碼實現,代碼在AbstractAutowireCapableBeanFactory的initializeBean方法中:
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                @Override
                public Object run() {
                    invokeAwareMethods(beanName, bean);
                    return null;
                }
            }, getAccessControlContext());
        }
        else {
            invokeAwareMethods(beanName, bean);
        }
// 開始Bean初始化前處理、初始化、初始化后處理
        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            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;
    }

可以看出來,aware接口的各種處理是在屬性設置完成之后、bean初始化之前完成的。顯然的,如果我們直接new出來一個bean,這些框架性的特性是沒有使用到的。但是上面提到的六中特殊的xxxAware,比如ApplicationContextAware,可以完成自動化在容器中進行接口注入,原來在應用中創建上下文容器時會注冊一個BeanPostProcessor------ApplicationContextAwareProcessor,在這個類里面進行了context的注入,這樣我們就能能夠拿到bean中的context對象:

public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
        AccessControlContext acc = null;

        if (System.getSecurityManager() != null &&
                (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                        bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                        bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
            acc = this.applicationContext.getBeanFactory().getAccessControlContext();
        }

        if (acc != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                @Override
                public Object run() {
                    invokeAwareInterfaces(bean);
                    return null;
                }
            }, acc);
        }
        else {
            invokeAwareInterfaces(bean);
        }

        return bean;
    }

然后在AbstractApplicationContext.prepareBeanFactory方法中,進行對ApplicationContextAwareProcessor的注入。

    // Configure the bean factory with context callbacks.
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

3、自定義aware接口實現

  • 知道原理后我們要實現自定義aware接口實現,需要完成下面兩個步驟:
    1.實現我們aware接口的postprocessor,并在容器中注冊;
    2.bean實體類集成我們自定義的aware接口并實現
  • 具體案例實現:
    (1)自定義aware接口:
public interface AppleAware {
    void setApple(Apple a);
}

(2)自定義Processor實現BeanPostProcessor接口

public class AppleAwarePostProcessor implements BeanPostProcessor {
 
    private Apple a;
 
    public AppleAwarePostProcessor(Apple a) {
        this.a = a;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(bean instanceof AppleAware) {
            ((AppleAware) bean).setApple(a);
        }
        return bean;
    }
 
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // TODO Auto-generated method stub
        return bean;
    }
 
}

(3)實現AppleAware 接口完成自定義bean注入

public class Market implements AppleAware {
 
    private Apple a;
 
    @Override
    public void setApple(Apple a) {
         this.a = a;
    }
 
    public String getName() {
        return a.getName();
    }
 
}

(4)測試

  • 一定要把我們的BeanPostProcessor加入到當前容器中,這一點非常重要
public class TestAware {
    public static void main(String args[]) {
        ConfigurableBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
        BeanPostProcessor bpp = new AppleAwarePostProcessor((Apple)beanFactory.getBean("apple"));
    // 工廠對象中加入我們自定義的BeanPostProcessor
        beanFactory.addBeanPostProcessor(bpp);
        Market market = (Market) beanFactory.getBean("market");
        System.out.println(market.getName());
    }
}

參考:
https://www.cnblogs.com/RunForLove/p/5828916.html

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,991評論 19 139
  • 1.1 spring IoC容器和beans的簡介 Spring 框架的最核心基礎的功能是IoC(控制反轉)容器,...
    simoscode閱讀 6,753評論 2 22
  • 1.1 Spring IoC容器和bean簡介 本章介紹了Spring Framework實現的控制反轉(IoC)...
    起名真是難閱讀 2,621評論 0 8
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,972評論 6 342
  • 本來是準備看一看Spring源碼的。然后在知乎上看到來一個帖子,說有一群**自己連Spring官方文檔都沒有完全讀...
    此魚不得水閱讀 6,952評論 4 21