黑莲技术资源论坛

作者: 顺势而为47
查看: 80|回复: 0

1.Spring源碼整體脈絡及注解的使用

1.Spring源碼整體脈絡及注解的使用

[复制链接]
顺势而为47 | 显示全部楼层 发表于: 2022-8-5 21:44:42
顺势而为47 发表于: 2022-8-5 21:44:42 | 显示全部楼层 |阅读模式
查看: 80|回复: 0
思維導圖︰點擊查看思維導圖
文章圖片︰點擊查看圖片
一、Spring框架功能整體介紹


1.Spring Core Container

模塊作用: Core 和 Beans 模塊是框架的基礎部分,提供 IOC(控制反轉)和 DI (依賴注入) 特性。 這里的基礎概念是 BeanFactory,它提供對 Factory 模式的經典實現來消除對程序性單例模式的需要,並真正地允許你從程序邏輯中分離出依賴關系和配置。
Core︰ 主要包含 Spring 框架基本的核心工具類, Spring 的其他組件都要用到這個包里的類,Core 模塊是其他組件的基本核心。
Beans︰(BeanFacotry的作用) 它包含訪問配置文件、創建和管理 bean 以及進行 Inversion Of Control / Dependency Injection ( IOC/DI )操作相關的所有類。(思考題 1)
Context︰(處理BeanFactory,以下還ApplicationContext的作用) 構建于 Core 和 Beans 模塊基礎之上,提供了一種類似 JNDI 注冊器的框架式的對象訪問方法。 Context 模塊繼承了 Beans 的特性,為 Spring 核心提供了大量擴展,添加了對國際化(例如資源綁定)、事件傳播、資源加載和對 Context 的透明創建的支持。Context 模塊同時也支持 J2EE 的一些特性, ApplicationContext 接口是 Context。
BeanFactory 和 ApplactionContext 的區別︰ (思考題 2)

  • BeanFactory 是懶加載的,ApplactionContext 是非懶加載的(可以指定為懶加載)
  • BeanFactory 只有一個職責就是調用 getBean() 生產 Bean,而 ApplactionContext 是 BeanFactoy 的擴展,是面向用戶的,有更多的實現(包括AOP、讀取資源文件、國際化、事件傳播等)
SPEL(Expression Language)︰ 提供了強大的表達式語言,用于在運行時查詢和操縱對象。
2.Spring Data Access/Integration

JDBC︰ 提供了一個 JDBC 抽象層,它可以消除冗長的JDBC編碼和解析數據庫廠商特有的錯誤代碼。 這個模塊包含了 Spring 對 JDBC 數據訪問進行封裝的所有類。
ORM︰ 如 JPA、Hibernate、iBatis 等,提供了 一個交互層。
OXM︰ Object/XML 映射實現包括 JAXB、 Castor、 XMLBeans、 JiBX 和 XStrearn
JMS︰ 包含了 一些制造和消費消息的特性
Transaction︰ 支持編程和聲明性的事務管理,這些事務類必須實現特定的接口,並且對所有的 POJO 都適用。
3.Spring Web

提供了基礎的面向 Web 的集成特性。例如,多文件上傳、使用 servlet listeners 初始化 IOC 容器以及一個面向 Web 的應用上下文。 它還包含 Spring 遠程支持中 Web 的相關部分。
4.Spring Aop

Aspects︰ 提供了對 AspectJ 的集成支持。
Instrumentation︰ 提供了 class instrumentation 支持和 classLoader 實現,使得可以在特定的應用服務器上使用
5.Test

支持使用 JUnit 和 TestNG
二、Spring IOC 容器底層注解使用

1.xml配置形式和配置類形式

基于xml的形式定義Bean的信息
<bean class="com.zhe.spring.HelloSpring">    <property name="car" ref="car"/></bean><!--  基于xml的形式定義Bean的信息  --><bean id="car" class="com.zhe.spring.Car"></bean>復制代碼// 1.基于xml的形式定義Bean的信息// ClassPathXmlApplicationContext解析xml,去容器中讀取BeanClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");log.debug(ctx.getBean("car").toString());復制代碼基于讀取配置類的形式定義Bean信息
@Configurationpublic class MainConfig {   @Bean   public Car car(){       return new Car();   }}復制代碼// 2.基于讀取配置類的形式定義Bean信息// 通過@Bean的形式是使用的話, bean的默認名稱是方法名,也可以通過@Bean(value="bean的名稱") 指定AnnotationConfigApplicationContext atx = new AnnotationConfigApplicationContext(MainConfig.class);log.debug(atx.getBean("car").toString());復制代碼2.在配置類上寫@CompentScan注解來進行包掃描

@Configuration @ComponentScan(basePackages = {"com.zhe.testcompentscan"}) public class MainConfig { }復制代碼排除用法 excludeFilters(排除@Controller注解的,和NotScanService的)
@Configuration @ComponentScan(basePackages = {"com.zhe.testcompentscan"},excludeFilters = {     @ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}),    @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {NotScanService.class}) })public class MainConfig {}復制代碼包含用法 includeFilters,注意,若使用包含的用法,需要把useDefaultFilters屬性設置為false(true表示掃描全部的)
// 掃描Controller和Service@Configuration @ComponentScan(basePackages = {"com.zhe.testcompentscan"},includeFilters = {              @ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class, Service.class}) },useDefaultFilters = false) public class MainConfig {}復制代碼public enum FilterType {     //注解形式 比如@Controller @Service @Repository @Component    ANNOTATION,     //指定的類型     ASSIGNABLE_TYPE,     //aspectJ形式的     ASPECTJ,     //正則表達式的     REGEX,     //自定義的     CUSTOM }復制代碼FilterType.CUSTOM 自定義類型如何使用
public class TestFilterType implements TypeFilter {     @Override     public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {     //獲取當前類的注解源信息     AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();     //獲取當前類的class的源信息     ClassMetadata classMetadata = metadataReader.getClassMetadata();     //獲取當前類的資源信息     Resource resource = metadataReader.getResource();     if(classMetadata.getClassName().contains("dao")) {        return true;    }    return false;}復制代碼@ComponentScan(basePackages = {"com.zhe.testcompentscan"},includeFilters = {     @ComponentScan.Filter(type = FilterType.CUSTOM,value = TestFilterType.class) },useDefaultFilters = false) public class MainConfig {}復制代碼3.配置Bean的作用域對象

在不指定 @Scope 的情況下,所有的 bean 都是單例的 bean,而且是餓漢加載(容器啟動實例就創建好了)
@Bean public Person person() {   return new Person(); }復制代碼指定 @Scope 為 prototype 表示為多實例的,而且還是懶加載
@Bean @Scope(value = "prototype") public Person person() {   return new Person(); }復制代碼@Scope 指定的作用域方法取值
a) singleton 單實例的(默認) b) prototype 多實例的  不能解決循環依賴c) request 同一次請求復用一個單例對象d) session 同一個會話級別復用一個單例對象e) application ServletContext的生命周期中復用一個單例對象f) websocket websocket的生命周期中復用一個對象復制代碼4.Bean的懶加載

@Lazy (主要針對單實例的 bean 容器啟動的時候,不創建對象,在第一次使用的時候才會創建該對象)
@Bean @Lazy public Person person() {     return new Person(); }復制代碼5.@Conditional 進行條件判斷

場景︰ 有兩個組件 TestAspect 和 TestLog,TestLog 組件是依賴于 TestAspect 的組件,當容器中有 TestAspect 時,TestLog 才會實例化
應用: 自己創建一個 TestCondition 的類實現 Condition 接口
public class TestCondition implements Condition {   @Override    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {    //判斷容器中是否有testAspect的組件    if(context.getBeanFactory().containsBean("testAspect")) {     return true;    }     return false;    } }復制代碼public class MainConfig {     @Bean public TestAspect testAspect() { return new TestAspect (); }    //當且 容器中有testAspect的組件,那麼testingLog才會被實例化.     @Bean     @Conditional(value = TestCondition.class)    public TestLog testLog() {         return new TestLog ();     } }復制代碼6.往 IOC 容器中添加組件的方式

6.1.通過 @CompentScan + @Controller @Service @Respository @Component

適用場景: 針對我們自己寫的組件可以通過該方式來進行加載到容器中
// 無論加哪個注解都是一樣的,僅為提高可讀性,推薦使用下面的方法@Controller:控制器,推薦給controller層添加此注解@Service:業務邏輯,推薦給業務邏輯層添加此注解@Repository:倉庫管理,推薦給數據訪問層添加此注解@Component:給不屬于以上基層的組件添加此注解復制代碼@Controller 是 @Component 的子組件
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic @interface Controller {    String value() default "";}復制代碼6.2. 通過 @Bean 的方式來導入組件(適用于導入第三方組件的類)

@Bean是一個方法級別的注解,它與 XML中的元素類似。注解支持 提供的一些屬性,例如 (init-method、destroy-method、autowiring、name ) 開發者可以在 @Configuration 類或 @Component 類中使用 @Bean 注解。
使用@Configuration注解類時,這個類的目的就是作為 bean 定義的地方。此外,@Configuration類允許通過調用同一個類中的其他@Bean方法來定義 bean 間依賴關系。
6.3.通過 @Import 來導入組件 (3 種方式,導入組件的id為全類名路徑)

// @Import 注解允許從另一個配置類加載@Bean定義@Configuration @Import(value = {Person.class, Car.class}) public class MainConfig { }復制代碼通過 @Import 的 ImportSeletor 類實現組件的導入 (導入組件的id為全類名路徑)
public class TestImportSelector implements ImportSelector {     //可以獲取導入類的注解信息    @Override     public String[] selectImports(AnnotationMetadata importingClassMetadata) {         return new String[]{"com.zhe.testimport.compent.Dog"};    } }€€@Configuration@Import(value = {Person.class, Car.class, TestImportSelector.class}) public class MainConfig { }復制代碼通過 @Import 的 ImportBeanDefinitionRegister 導入組件 (可以指定 bean 的名稱)
public class TestBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {     @Override     public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {         // 創建一個bean定義對象         RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Cat.class);         // 把bean定義對象導入到容器中        registry.registerBeanDefinition("car",rootBeanDefinition);     } }€€@Configuration // @Import(value = {Person.class, Car.class}) // @Import(value = {Person.class, Car.class, TestImportSelector.class}) @Import(value = {Person.class, Car.class, TestImportSelector.class, TestBeanDefinitionRegister.class}) public class MainConfig {€€}復制代碼6.4.通過實現 FacotryBean 接口來實現注冊組件(適合復雜初始化的Bean)

public class CarFactoryBean implements FactoryBean<Car> {         //返回bean的對象         @Override         public Car getObject() throws Exception {                 return new Car();         }        //返回bean的類型         @Override     public Class<?> getObjectType() {                 return Car.class;         }        //是否為單例         @Override         public boolean isSingleton() {                 return true;         } }復制代碼7.Bean的初始化方法和銷毀方法

什麼是 Bean 的生命周期? bean的創建--->初始化--->銷毀方法
由容器管理 Bean 的生命周期,我們可以通過自己指定 bean的 初始化方法和 bean 的銷毀方法。

  • 針對單實例 bean 的話,容器啟動的時候,bean 的對象就創建了(默認懶加載),而且容器銷毀的時候,也會調用bean 的銷毀方法
  • 針對多實例 bean 的話,容器啟動的時候,bean 是不會被創建的而是在獲取 bean 的時候被創建,而且 bean 的銷毀不受 IOC 容器的管理
@Configuration public class MainConfig {     //指定了bean的生命周期的初始化方法和銷毀方法.    @Bean(initMethod = "init",destroyMethod = "destroy")     public Car  car() {         return new Car();     }         public void init(){        // 初始化    }        public void destroy(){        // 銷毀    }}復制代碼通過 InitializingBean 和 DisposableBean 的二個接口實現 bean 的初始化以及銷毀方法
@Component public class Person implements InitializingBean,DisposableBean {     public Person() {         System.out.println("Person的構造方法");     }        @Override         public void destroy() throws Exception {         System.out.println("DisposableBean的destroy()方法 "); }    @Override     public void afterPropertiesSet() throws Exception {                                                  System.out.println("InitializingBean的 afterPropertiesSet方法");     } }復制代碼通過JSR250規範 提供的注解 @PostConstruct 和 @ProDestory 標注的方法
@Component public class Book {     public Book() {         System.out.println("book 的構造方法");     }        @PostConstruct     public void init() {         System.out.println("book 的PostConstruct標志的方法");    }        @PreDestroy     public void destory() {         System.out.println("book 的PreDestory標注的方法");     } }復制代碼通過 Spring 的 BeanPostProcessor 的 bean 的後置處理器會攔截所有 bean 創建過程執行順序 Spring IOC 容器實例化 Bean => 調用BeanPostProcessor 的 postProcessBeforeInitialization 方法 => 調用 bean 實例的初始化方法 => 調用 BeanPostProcessor 的 postProcessAfterInitialization 方法

  • postProcessBeforeInitialization 在 init 方法之前調用
  • postProcessAfterInitialization 在 init 方法之後調用
@Component public class TestBeanPostProcessor implements BeanPostProcessor {         // init方法之前調用        @Override         public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {                 System.out.println("...postProcessBeforeInitialization:" + beanName);                 return bean;         }        // init方法之後調用        @Override         public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {                System.out.println("...postProcessAfterInitialization:" + beanName);                 return bean;          } }復制代碼BeanFactoryPostProcessor bean工廠的 bean 屬性處理容器,用于管理我們的 Bean 工廠內所有的 Beandefinition(未實例化)數據,可以隨心所欲的修改實例屬性。
@Componentpublic class TestMyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {    @Override    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {        System.out.println("TestMyBeanFactoryPostProcessor...postProcessBeanFactory...");        int count = beanFactory.getBeanDefinitionCount();        String[] names = beanFactory.getBeanDefinitionNames();        System.out.println("當前BeanFactory中有"+count+" 個Bean");        System.out.println(Arrays.asList(names));    }}復制代碼8.通過 @Value + @PropertySource 來給組件賦值

public class Person {         //通過普通的方式         @Value("值")         private String firstName;         //spel方式來賦值         @Value("#{38-8}")         private Integer age;         //通過讀取外部配置文件的值         @Value("${person.lastName}")         private String lastName; }@Configuration @PropertySource(value = {"classpath:person.properties"}) //指定外部文件的位置 public class MainConfig {     @Bean     public Person person() {                 return new Person();         } }復制代碼9.自動裝配

9.1.@Autowired的使用

自動注入:
//一個Dao @Repository public class TestDao {}@Service public class TestService {         @Autowired         private TestDao testDao; }復制代碼注意︰

  • 使用 @Autowired 注解時,自動裝配的時候是根據類型實現的。
  • 1、如果只找到一個,則直接進行賦值,
  • 2、如果沒有找到,則直接拋出異常,
  • 3、如果找到多個,那麼會按照變量名作為 id 繼續匹配,
  • 1、匹配上直接進行裝配
  • 2、如果匹配不上則直接報異常
  • 假設我們需要指定特定的組件來進行裝配,我們可以通過使用@Qualifier("testDao")來指定裝配的組件或者在配置類上的 @Bean 加上 @Primary 注解
  • 假設我們容器中沒有,那麼在裝配的時候就會拋出異常,不拋異常就指定@Autowired(required = false)
  • /** * 當方法上有@AutoWired注解時︰ * 1、此方法在bean創建的時候會自動調用 * 2、這個方法的每一個參數都會自動注入值 * @param personDao */ @Autowired public void test(PersonDao personDao){ System.out.println("此方法被調用:"+personDao); } €€ /** * @Qualifier注解也可以作用在屬性上,用來被當作id去匹配容器中的對象,如果沒有 * 此注解,那麼直接按照類型進行匹配 * @param personService */ @Autowired public void test2(@Qualifier("personServiceExt") PersonService personService){ System.out.println("此方法被調用︰"+personService); } 復制代碼
9.2.@Resource(JSR250規範)

功能和 @Autowired 的功能差不多一樣,但是不支持 @Primary 和 @Qualifier。@Autowired只適合Spring 框架,而@Resource 擴展性更好。@Autowired 是 spring 中提供的注解,@Resource 是 JDK 中定義的注解,依靠的是 Java 的標準
9.3.@InJect(JSR330規範)

<dependency>     <groupId>javax.inject</groupId>     <artifactId>javax.inject</artifactId>     <version>1</version> </dependency>復制代碼需要導入jar包依賴。功能和支持@Primary功能 ,但是沒有Require=false的功能
10.自己編寫的組件需要使用 IOC 底層組件時(比如 ApplicationContext 等)可以通過實現XXXAware接口來實現

@Component public class TestCompent implements ApplicationContextAware,BeanNameAware {     private ApplicationContext applicationContext;     @Override     public void setBeanName(String name) {         System.out.println("current bean name is :【"+name+"】");     }        @Override     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {         this.applicationContext = applicationContext;     } }復制代碼11.@Profile注解

通過@Profile注解來根據環境來激活標識不同的Bean

  • @Profile標識在類上,那麼只有當前環境匹配,整個配置類才會生效
  • @Profile標識在Bean上 ,那麼只有當前環境的Bean才會被激活
  • 沒有標志為@Profile的bean 不管在什麼環境都可以被激活
//標識為測試環境才會被裝配 @Bean @Profile(value = "test") public DataSource testDs() {         return buliderDataSource(new DruidDataSource()); }復制代碼激活切換環境的方法:
// 方法一 -Dspring.profiles.active=test|dev|prod // 方法二public static void main(String[] args) {    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();     ctx.getEnvironment().setActiveProfiles("test","dev");     ctx.register(MainConfig.class);     ctx.refresh();     printBeanName(ctx); } 復制代碼三、Spring 源碼的整體脈絡


1.控制反轉和依賴注入

IOC容器的核心思想︰ 資源不由使用資源的雙方管理,而由不使用資源的第三方管理,這可以帶來很多好處。

  • 資源集中管理,實現資源的可配置和易管理
  • 降低了使用資源雙方的依賴程度,也就是我們說的耦合度(解耦)
  • 可維護性、靈活性、擴展性變高
控制反轉(Inversion of control)︰ (思考題 6) 創建對象的控制權進行轉移,以前創建對象的主動權和創建時機是由自己把控的(new),而現在這種權力轉移到第三方,比如轉移交給了 IOC 容器,它就是一個專門用來創建對象的工廠,你要什麼對象,它就給你什麼對象,有了 IC容器,依賴關系就變了,原先的依賴關系就沒了,它們都依賴 IOC 容器了,通過 IOC 容器來建立它們之間的關系。
依賴注入(Dependency injection)︰ 控制反轉之後,獲得依賴對象的過程由自身管理變為有 IOC 容器自動注入。依賴注入是實現 IOC 的方法,就是有 IOC 容器在運行期間,動態的將某種依賴關系注入到對象當中。
我們的類要生產成一個 Bean 不是一步到位的,它會涉及很多繁雜的步驟︰ (思考題3&4&5)
什麼是 BeanDefinition 呢?
用來描述 Bean 的,存放關于 Bean 的一些列信息,例如︰單例、多例、作用域、Bean對應的Class、是否懶加載等等。



  • BeanDefinition 元數據信息,返回該 Bean 的來源
  • AttributeAccessor 提供對 BeanDefinition 屬性操作能力
1.首先要將類加載成 BeanDefinition (Bean定義)
XML 配置的類可以讀取成 Bean,Annotation (注解) 配置的類也可以讀取 Bean ,但是這兩種 Bean 配置方式又不同 ,因此引申出統一的 Bean 定義︰BeanDefinition
XML 和 Annotation 都會被先被讀成 BeanDenfintion (里面包含了大量屬性︰限定類名、單例、多例等)。這個過程也包含一些列的復雜步驟︰

  • a.讀取配置類︰ BeanDefinitionReader 負責讀取配置類,基于注解和 XML,又有 AnnotatedBeanDefinitionReader 、XmlBeanDefinitionReader讀xml和Annotation 去讀取各自的配置
  • b.掃描配置類︰ BeanDefinitionSacnner 負責掃描配置類 @Compontent。@Component 中可以添加有一些列的限制條件,BeanDefinitionSacnner 可以將符合條件的類讀取到容器中,用于注冊 BeanDenfintion
  • c.注冊Bean定義︰ 最後由 BeanDefinitionRegistry 注冊 BeanDenfintion 放入 BeanDefinitionMap 中
在這個過程中 ApplicationContext 還提供了擴展點來對 BeanDenfintion 進行擴展,Spring 生態除了 IOC 都需要這些擴展點來實現。它是 Spring 生態核心。如果我們需要集成使用很多其他框架(MyBatis、JPA等)都是通過這些擴展點去實現的。
修改 BeanDefinition 的擴展點
可以修改 BeanDefinition,只需要實現 BeanFactoryPostProcessor 接口,重寫方法

  • postProcessBeanFactory BeanDefinition 的後置處理器,可修改Bean定義
添加 BeanDefinition 的擴展點
可以添加 BeanDefinition ,只需要實現 BeanDefinitionRegistryPostProcessor 重寫方法

  • postProcessBeanDefinitionRegistry 注冊 BeanDefinition,實現後會多注冊 Bean
2.然後通過 BeanFactory 構造 Bean 存入一個 Map 中
通過 BeanFactory (簡單工廠模式) 調用 getBean() 將 BeanDefinition 進行一些列的操作 (實例化、填充屬性、初始化) 後將 Bean put 到一個 Map 中 (單例池緩存)。

  • a.實例化 (Instantiation)
  • 實例化後,此時還未自動裝配,未生成 Bean 實體
  • b.填充屬性 (Populate)
  • 在填充屬性的過程中,可能會存在 A 引用了 B,B 又引用了 A 的情況,就可能產生循環依賴,Spring 為了解決這個問題引入了三級緩存 (三個 Map)
  • c.初始化 (Initialization)
  • 初始化的過程中還會調用一堆 Aware (初始化生命周期接口),最後將初始化好的 Bean put 到一個 Map<key,value> 中去,這個Map是一個單例池緩存,實際就是一個 ConcurrentHashMap 保存起來,我們調用 getBean()就是從這個 Map 中拿
  • key :bean的名稱,Value bean實例
實例化的兩種方式︰

  • 反射︰Spring 自己控制 @Component 只會將類的 class 注入到 BeanDefinition 中
  • 工廠方法︰更靈活,可以自己去new , @Bean,里面可以自由控制 Bean 實例,new,賦值等
@Beanpublic Car car(){    return new Car();}復制代碼在調用 getBean() 過程中會涉及到九處後置處理器的調用,在創建時前後,實例化前後,填充屬性前後,初始化前後等
 實現 InstantiationAwareBeanPostProcessor

  • postProcessBeforelnstantiation 直接返回 Bean 停止後面的流程
 實現 SmartInstantiationAwareBeanPostProcessor

  • determineCandidateConstructors 指定實例化構造函數
 實現 MergedBeanDefinitionPostProcessor

  • postProcessMergedBeanDefinition @AutoWired @Value 預解析
 實現 SmartInstantiationAwareBeanPostProcessor

  • getEarlyBeanReference 解決循環引用 AOP
 實現 InstantiationAwareBeanPostProcessor

  • postProcessAfterInstantiation 終止賦值
 實現 InstantiationAwareBeanPostProcessor

  • postProcessPropertyValues 注入屬性PropertyValues @AutoWired 在這里進行依賴注入
 實現 BeanPostProcess

  • postProcessBeforeInitialization 初始化前調用@PostConstruct
  • postProcessAfterInitialization 初始化後 AOP: 創建代理
 DestructionAwareBeanPostProcessor

  • requiresDestruction
思考題︰
1.描述 BeanFactory
2.BeanFactory 和 ApplicationContext 的區別?
3.簡述 SpringIOC 的加載過程
4.簡述 Bean 的生命周期
5.Spring 中有哪些擴展接口及調用時機
6.控制反轉和依賴注入是什麼

作者︰Hz488
鏈接︰https://juejin.cn/post/7127999778390016030

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|小黑屋|黑莲技术资源论坛 ( 闽ICP备18016623号-7 )|网站地图

GMT+8, 2022-8-19 04:16 , Processed in 0.674079 second(s), 26 queries .

Powered by BBS.HL1.NET X3.4 © 2020-2022

本站IT社区(bbs.hl1.net)所有的资源教程均来自网友分享及互联网收集

快速回复 返回顶部 返回列表