Spring重要的類和接口


一、BeanDefinition 接口

說到BeanDefinition,就要說到java的核心思想了,萬物皆對象。眾所周知,java是面向對象的編程語言,所有的事務都可以用一個對象來描述,jdk提供了用來描述類的類Class,spring為了能更好的描述bean,也提供了一個類,那就是BeanDefinition。簡而言之,BeanDefinition就是用來描述bean的類。

執行時機:讀取bean時,就會使用,生成對應的BeanDefinition對象

/**
 *
 * BeanDefinition用來描述bean的類,該實例具有屬性值。
 *
 */
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
 
    /**
     * 單例
     * 
     */
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
 
    /**
     * 原型即多例
     * 
     */
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
 
 
    /**
     * 
     */
    int ROLE_APPLICATION = 0;
 
    /**
     * 
     * ROLE_SUPPORT = 1 表示這個類是用戶本身的,是從配置文件中過來的
     */
    int ROLE_SUPPORT = 1;
 
    /**
     *
     * ROLE_INFRASTRUCTURE = 2 表示這個bean是spring自己的
     */
    int ROLE_INFRASTRUCTURE = 2;
 
    /**
     * 父類的名字
     */
    void setParentName(@Nullable String parentName);
 
    @Nullable
    String getParentName();
 
    /**
     * bean 的 class name
     */
    void setBeanClassName(@Nullable String beanClassName);
 
    @Nullable
    String getBeanClassName();
 
    /**
     * 作用域
     */
    void setScope(@Nullable String scope);
 
    @Nullable
    String getScope();
 
    /**
     * 是否懶加載
     */
    void setLazyInit(boolean lazyInit);
    
    boolean isLazyInit();
 
    /**
     * 依賴
     */
    void setDependsOn(@Nullable String... dependsOn);
 
    @Nullable
    String[] getDependsOn();
    
    void setAutowireCandidate(boolean autowireCandidate);
 
    /**
     *
     * 是否啟用自動裝配
     */
    boolean isAutowireCandidate();
 
    /**
     * primary標注,表示優先注入,優先使用
     */
    void setPrimary(boolean primary);
 
    boolean isPrimary();
 
    /**
     * 工廠名字
     *
     */
    void setFactoryBeanName(@Nullable String factoryBeanName);
 
    @Nullable
    String getFactoryBeanName();
 
    /**
     * 工廠方法名字
     */
    void setFactoryMethodName(@Nullable String factoryMethodName);
 
    @Nullable
    String getFactoryMethodName();
 
    /**
     *
     * 返回此bean的構造函數參數值。
     */
    ConstructorArgumentValues getConstructorArgumentValues();
 
    /**
     *
     * 構造方法是否有構造參數
     * @since 5.0.2
     */
    default boolean hasConstructorArgumentValues() {
        return !getConstructorArgumentValues().isEmpty();
    }
 
    MutablePropertyValues getPropertyValues();
 
    /**
     * Return if there are property values values defined for this bean.
     * @since 5.0.2
     */
    default boolean hasPropertyValues() {
        return !getPropertyValues().isEmpty();
    }
 
    /**
     *
     * spring bean初始化完成調用的方法的名字
     *
     */
    void setInitMethodName(@Nullable String initMethodName);
 
    @Nullable
    String getInitMethodName();
 
    /**
     * spring bean銷毀前調用的方法的名字
     */
    void setDestroyMethodName(@Nullable String destroyMethodName);
 
    @Nullable
    String getDestroyMethodName();
 
    void setRole(int role);
 
    int getRole();
 
    /**
     *
     * bean 描述
     * Set a human-readable description of this bean definition.
     * @since 5.1
     */
    void setDescription(@Nullable String description);
 
    @Nullable
    String getDescription();
 
 
    // Read-only attributes
 
    /**
     *
     * 是否是單例
     */
    boolean isSingleton();
 
    /**
     * 是否是原型 即多例
     */
    boolean isPrototype();
 
    /**
     *
     * 是否是抽象
     */
    boolean isAbstract();
 
    @Nullable
    String getResourceDescription();
 
    @Nullable
    BeanDefinition getOriginatingBeanDefinition();
 
}

從源碼中可以看出BeanDefinition具有多個屬性,可以用來描述bean,其中beanClassName可以用來存儲bean的class,方便后面通過反射創建對象。scope、lazyInit、autowireCandidate等也都是重要屬性。

 

  • BeanMetadataElement接口:BeanDefinition元數據,返回該Bean的來源
  • AttributeAccessor接口:提供對BeanDefinition屬性操作能力,
  • AbstractBeanDefinition類:抽象類統一實現了BeanDefinition定義的一部分操作,可以說是定義了BeanDefinition很多默認的屬性。 正是在AbstractBeanDefinition基礎上, Spring衍生出了一些列BeaDefinition。
AbstractBeanDefinition上衍生出來的幾個類:
  • RootBeanDefinition:代表一個xml,java Config來的BeanDefinition

  • ChildBeanDefinition:可以讓子BeanDefinition定義擁有從父母哪里繼承配置的能力

  • GenericBeanDefinition:spring2.5后注冊bean首選的是GenericBeanDefinition。GenericBeanDefinition允許動態的設置父bean.GenericBeanDefinition可以作為RootBeanDefinition與ChildBeanDefinition的替代品。

  • AnnotatedBeanDefinition接口:表示注解類型BeanDefinition。有兩個重要的屬性,AnnotationMetadata,MethodMetadata分別表示BeanDefinition的注解元信息和方法元信息
    實現了此接口的BeanDefinition可以獲取到注解元數據和方法元數據。

  • AnnotatedGenericBeanDefinition類:表示@Configuration注解注釋的BeanDefinition類

  • ScannedGenericBeanDefinition類:表示@Component、@Service、@Controller等注解注釋的Bean類

BeanDefinitionRegistry 接口
具有增,查,刪BeanDefinition的能力。一次只能注冊一個BeanDefinition。
實現類SimpleBeanDefinitionRegistry,DefaultListableBeanFactory,GenericApplicationContext等。一般實現類里都都有一個private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap()來存儲BeanDefinition。
BeanDefinitionReader接口

既可以使用BeanDefinitionRegistry構造。也可以通過loadBeanDefinitions把配置加載為多個BeanDefinition並注冊到BeanDefinitionRegistry中。可以說是高效版本的BeanDefinitionRegistry。

實現類有

  • XmlBeanDefinitionReader從xml中讀取BeanDefinition;
  • PropertiesBeanDefinitionReader從Properties文件讀取BeanDefinition
AnnotatedBeanDefinitionReader類

對帶有注解的BeanDefinition進行注冊

ClassPathBeanDefinitionScanner類

可以掃描到@Component @Repository @Service @Controller 的BeanDefinition注冊到容器中。

BeanDefinitionHolder
BeanDefinition包裝類。

二、BeanFactory和FactoryBean

有很多人弄不清楚BeanFactory和FactoryBean的區別,BeanFactory是創建bean的工廠,我們常說的spring 容器(存儲spring bean的map)就是在BeanFactory中定義的。而FactoryBean是spring提供的一個特殊的bean,通過FactoryBean我們也可以將一個普通class注冊到spring容器中。 

BeanFactory
Object getBean(String name) throws BeansException;

<T> T getBean(String name, Class<T> requiredType) throws BeansException;

Object getBean(String name, Object... args) throws BeansException;

<T> T getBean(Class<T> requiredType) throws BeansException;

<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

從源碼中可以看出BeanFactory提供了很多getBean方法,這個方法就是根據不同的參數來獲取bean對象。BeanFactory是一個工廠用來存儲和創建bean的。

FactoryBean

FactoryBean是spring提供的一個特殊的bean,實現此接口的bean可以往spring容器中添加一個bean。

@Component("indexFactoryBean")
public class IndexFactoryBean implements FactoryBean {
 
 
    @Override
    public Object getObject() throws Exception {
        IndexDao indexDao = new IndexDao();
        return indexDao;
    }
 
    @Override
    public Class<?> getObjectType() {
        return IndexDao.class;
    }
}
 
 
public class Test {
 
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
 
        Object indexFactoryBean = context.getBean("indexFactoryBean");
        System.out.println(indexFactoryBean.getClass());
    }
}

執行結果:

indexDao
class com.wangcongming.demo.service.IndexDao

可以發現IndexFactoryBean注冊到spring容器中的對象是IndexDao,這就是spring中FactoryBean提供的功能。FactoryBean中getObject()方法可以返回一個對象,spring容器初始化的過程中會將getObject()返回的對象添加到spring容器中。那么如果想獲取IndexFactoryBean本身的對象怎么辦呢?只需在bean name前加&即可取出

public class Test {
 
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
 
        Object indexFactoryBean = context.getBean("indexFactoryBean");
        System.out.println(indexFactoryBean.getClass());
 
        Object indexFactoryBean2 = context.getBean("&indexFactoryBean");
        System.out.println(indexFactoryBean2.getClass());
    }
}

執行結果:

indexDao
class com.wangcongming.demo.service.IndexDao
class com.wangcongming.demo.service.IndexFactoryBean

三、BeanFactoryPostProcessor

執行時機:工廠初始化完成之后,在bean被創建成對象之前執行

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

BeanFactoryPostProcessor 工廠后置處理器,它是在工廠初始化完成之后調用,它可以對bean進行修改,是spring提供的一個擴展點。postProcessBeanFactory()方法將factory傳入進去了,可以通過factory進行操作。

BeanDefinitionRegistryPostProcessor

執行時機:是BeanFactoryPostProcessor的子類,會在BeanFactoryPostProcessor之前進行執行

它是BeanFactoryPostProcessor的擴充接口,他擴充了一個方法:

void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

可以看到這個方法將registry傳入進來了,這意味着我們可以通過registry向容器中添加bean

四、BeanPostProcessor

bean后置處理器,會在bean初始化完成之后回調該接口的方法。

執行時機:bean對象創建完成,還未放入容器中時執行

@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
}
 
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    return bean;
}

這兩個方法有什么區別呢?  postProcessBeforeInitialization方法會在postProcessAfterInitialization之前回調,值得注意的是postProcessAfterInitialization方法的回調是在所有的BeanPostProcessor的postProcessBeforeInitialization方法執行完成之后。

五、InitializingBean

InitializingBean接口為bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是繼承該接口的類,在初始化bean的時候會執行該方法(創建出bean實例后)。

在spring初始化bean的時候,如果該bean是實現了InitializingBean接口,並且同時在配置文件中指定了init-method,系統則是先調用afterPropertiesSet方法,然后在調用init-method中指定的方法。 

spring要求這個init-method方法是一個無參數的方法。

注意這個順序:

  1. @PostConstruct注解標注的方法(JSR250)
  2. 實現InitializingBean接口的afterPropertiesSet方法(Spring的接口)
  3. 使用@Bean注解屬性initMethod自定義的方法(Spring提供)

六、DisposableBean 

該接口的作用是:允許在容器銷毀該bean的時候獲得一次回調。DisposableBean接口也只規定了一個方法:destroy。

關於在spring  容器初始化 bean 和銷毀前所做的操作定義方式還有以下種:

  • 通過@PostConstruct和@PreDestroy注解實現初始化和銷毀bean之前進行的操作。
  • 通過在xml中定義init-method和destory-method方法。

注意:

多例bean的生命周期不會由Spring容器來管理,說的簡單一點,多例bean其實就是自生自滅的,和容器沒有關系。 ,這里的DisposableBean中的方法是由Spring容器來調用的,所以如果一個多例實現了DisposableBean是沒有啥意義的,因為相應的方法根本不會被調用,當然在XML配置文件中指定了destroy方法,也是沒有意義的。 

七、**Aware接口

Spring框架提供了多個*Aware接口,用於輔助Spring Bean以編程的方式調用Spring容器。通過實現這些接口,可以增強Spring Bean的功能,但是也會造成對Spring容器的綁定。

  • ApplicationContextAware:Spring框架啟動時,ApplicationContext初始化實現了該接口的Spring Bean時,會將ApplicationContext的引用作為參數傳遞給創建的Bean實例,創建的Bean實例可以通過ApplicationContext的引用操作Spring框架的各種資源。
  • ApplicationEventPublisherAware:應用事件發布器,用於發布事件。
  • BeanClassLoaderAware:加載Spring Bean的類加載器。
  • BeanFactoryAware:獲得當前bean Factory,從而調用容器的服務
  • BootstrapContextAware:資源適配器BootstrapContext,如JCA,CCI
  • BeanNameAware:獲得到容器中Bean的名稱
  • EmbeddedValueResolverAware:通過 EmbeddedValueResolverAware 接口可以獲取spring容器加載的一些屬性值。
  • EnvironmentAware:獲取Environment對象。Environment是Spring的核心組件之一,可以理解為ApplicationContext的運行時環境,從中我們可以獲取操作系統信息、配置文件(application.properties等)中定義的屬性信息等。
  • ImportAware:可以獲取到導入該配置類接口的數據配置,是需要與@Import一起使用的。
  • MessageSourceAware:得到message source從而得到文本信息
  • NotificationPublisherAware:JMX通知
  • ResourceLoaderAware:獲取資源加載器,可以獲得外部資源文件
  • ServletConfigAware:獲取ServletConfig
  • ServletContextAware:獲取ServletContext
ApplicationContextAware 

1、為什么需要ApplicationContextAware?

在某些類中我們經常需要通過ApplicationContext來獲取需要的bean,但每一次使用new ClassPathXmlApplicationContext()都會重新裝配文件並實例化上下文bean,這樣肯定是很麻煩的,此時ApplicationContextAware接口的作用就體現出來了——spring會給實現此接口的類注入ApplicationContext對象

2、如何使用?

通常我們是寫一個AppContextUtil工具類

mport org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class AppContextUtil implements ApplicationContextAware {
    // 定義靜態ApplicationContext
    private static ApplicationContext applicationContext = null;
    /**
     * 重寫接口的方法,該方法的參數為框架自動加載的IOC容器對象
     * 該方法在啟動項目的時候會自動執行,前提是該類上有IOC相關注解,例如@Component
     * @param applicationContext ioc容器
     * @throws BeansException e
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // 將框架加載的ioc賦值給全局靜態ioc
        AppContextUtil.applicationContext = applicationContext;
        log.info("==================ApplicationContext加載成功==================");
    }
    // 獲取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
    // 通過name獲取 Bean.
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }
    // 通過class獲取Bean.
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }
    // 通過name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }  
}

3、spring何時注入上下文?

通過源碼跟蹤了解到AbstractApplicationContext.class下的refresh()方法中的prepareBeanFactory這句跟Aware有關,我們還可以看到:ApplicationContextAware是在spring初始化完bean后才注入上下文的

 prepareBeanFactory方法中涉及到上圖紅圈圈這個類,此類中的方法postProcessBeforeInitialization調用了此類中的invokeAwareInterfaces方法:

看到沒,上圖畫圈圈的地方就是spring對實現ApplicationContextAware接口的類調用setApplicationContext進行上下文注入

八、ApplicationEvent抽象類

是個抽象類,里面只有一個構造函數和一個長整型的timestamp。

spring事件使用步驟如下:

  • 自定義事件:實現ApplicationEvent。
  • 定義監聽器:實現 ApplicationListener
  • 使用容器對事件進行發布

1、自定義事件

public class TestEvent extends ApplicationEvent {

    private String name;

    private String msg;

    public TestEvent(Object source){
        super(source);
    }

    public TestEvent(Object source, String name, String msg) {
        super(source);
        this.name = name;
        this.msg = msg;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

2、定義監聽器

@Component
public class TestEventListener implements ApplicationListener<TestEvent> {

    @Override
    public void onApplicationEvent(TestEvent testEvent) {
        System.out.println("姓名:"+testEvent.getName()+"得到消息:"+testEvent.getMsg());
    }
}

3、使用容器發布事件

@Component
public class TestEventPublisher {

    @Autowired
    private ApplicationContext applicationContext;

    public void pushlish(String name, String msg){
        applicationContext.publishEvent(new TestEvent(this, name,msg));
    }
}

九、ApplicationListener接口

是一個接口,里面只有一個onApplicationEvent方法。所以自己的類在實現該接口的時候,要實現該方法。

十、Enable***

  • @EnableAspectJAutoProxy:開啟對AspectJ自動代理的支持。
  • @EnableAsync:開啟異步方法支持。
  • @EnableScheduling:開啟計划任務
  • @EnableWebMvc:開啟Web Mvc配置功能

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM