Spring-IOC部分

Spring-IOC部分

1.SpringBean的配置詳解(Bean標簽)

image-20250404142237565

(1)scope

默認情況下,單純的Spring環境Bean的作用范圍有兩個:Singleton和Prototype

singleton:單例,默認值,Spring容器創建的時候,就會進行Bean的實例化,并存儲到容器內部的單例池中,每次getBean時都是從單例池中獲取相同的Bean實例;

prototype:原型,Spring容器初始化時不會創建Bean實例,當調用getBean時才會實例化Bean,每次getBean都會創建一個新的Bean實例。生成的Bean不會存在單例池中

(2)lazy-init

當lazy-init設置為true時為延遲加載,也就是當Spring容器創建的時候,不會立即創建Bean實例,等待用到時在創建Bean實例并存儲到單例池中去,后續在使用該Bean直接從單例池獲取即可,本質上該Bean還是單例的

(3)init-method

可以在Bean中創建一個成員方法init,在Bean被實例化之后執行,或者實現InitializingBean 接口重寫afterPropertiesSet方法

(4)Bean實例化配置

1.構造方式實例化:底層通過構造方法對Bean進行實例化

  • 無參構造

  • 有參構造

    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"><constructor-arg name="name" value="haohao"/>
    </bean>
    

2.工廠方式實例化:底層通過調用自定義的工廠方法對Bean進行實例化

  • 靜態工廠方法實例化Bean

    靜態工廠方法實例化Bean,其實就是定義一個工廠類,提供一個靜態方法用于生產Bean實例,在將該工廠類及其靜態方法配置給Spring即可

    //工廠類
    public class UserDaoFactoryBean {//非靜態工廠方法public static UserDao getUserDao(String name){//可以在此編寫一些其他邏輯代碼return new UserDaoImpl();}
    }
    
    <bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean" factory-method="getUserDao"><constructor-arg name="name" value="haohao"/>
    </bean>
    
    • 靜態工廠方法是一個普通的靜態方法,它負責創建并返回一個對象實例。
    • 靜態工廠方法本身不會被 Spring 容器管理,因為它是一個靜態方法,不屬于任何 Spring Bean。
  • 實例工廠方法實例化Bean

    <!-- 配置實例工廠Bean -->
    <bean id="userDaoFactoryBean2" class="com.itheima.factory.UserDaoFactoryBean2"/>
    <!-- 配置實例工廠Bean的哪個方法作為工廠方法 -->
    <bean id="userDao" factory-bean="userDaoFactoryBean2" factory-method="getUserDao"><constructor-arg name="name" value="haohao"/>
    </bean>
    
  • 實現FactoryBean規范延遲實例化Bean

    public interface FactoryBean<T> {String OBJECT_TYPE_ATTRIBUTE = “factoryBeanObjectType”;T getObject() throws Exception; //獲得實例對象方法Class<?> getObjectType(); //獲得實例對象類型方法default boolean isSingleton() {return true;}
    }
    
    public class UserDaoFactoryBean3 implements FactoryBean<UserDao> {public UserDao getObject() throws Exception {return new UserDaoImpl();}public Class<?> getObjectType() {return UserDao.class;}
    }
    
    <bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean3"/>
    

    Spring容器創建時,FactoryBean被實例化了,并存儲到了單例池singletonObjects中,但是getObject() 方法尚未被執行,UserDaoImpl也沒被實例化,當首次用到UserDaoImpl時,才調用getObject() ,此工廠方式產生的Bean實例不會存儲到單例池singletonObjects中,會存儲到 factoryBeanObjectCache 緩存池中,并且后期每次使用到userDao都從該緩存池中返回的是同一個userDao實例。

(5)Bean的依賴注入配置

image-20250404144107704

構造器方法注入就和使用有參構造器實例化Bean的方式一樣

自動裝配

如果被注入的屬性類型是Bean引用的話,那么可以在 標簽中使用 autowire 屬性去配置自動注入方式,屬性值有兩個:

byName:通過屬性名自動裝配,即去匹配 setXxx 與 id=“xxx”(name=“xxx”)是否一致;

byType:通過Bean的類型從容器中匹配,匹配出多個相同Bean類型時,報錯。

<bean id="userService" class="com.itheima.service.impl.UserServiceImpl" autowire="byType">

基于注解的依賴注入

image-20250404161351686

@Value("${jdbc.username}")
private String username;
@Value("${jdbc.username}")
public void setUsername(String username){
System.out.println(username);
}//使用在屬性上直接注入
@Autowired
private UserDao userDao;
//使用在方法上直接注入
@Autowired
public void setUserDao(UserDao userDao){
System.out.println(userDao);
}@Autowired
@Qualifier("userDao2")
private UserDao userDao;//@Resource注解既可以根據類型注入,也可以根據名稱注入,無參就是根據類型注入,有參數就是根據名稱注入 是javax包下
@Resource
private UserDao userDao;
@Resource(name = "userDao2")
public void setUserDao(UserDao userDao){
System.out.println(userDao);
}

(6)Spring其他的配置標簽

Spring 的 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 
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    </beans>
    

    image-20250404144744969

  • 自定義標簽:就是需要額外引入其他命名空間約束,并通過前綴引用的標簽,例如 context:property-placeholder/ 標簽

在使用注解開發中,使用@Component注解代替標簽,其他標簽就可以定義一個配置類來替代原有的xml配置文件

@Configuration注解標識的類為配置類,替代原有xml配置文件,該注解第一個作用是標識該類是一個配置類,第二個作用是具備@Component作用

@ComponentScan 組件掃描配置,替代原有xml文件中的<context:component-scan base-package=“”/>

@PropertySource 注解用于加載外部properties資源配置,替代原有xml中的<context:property placeholder location=“”/>配置

@Import 用于加載其他配置類,替代原有xml中的配置

(7)基于注解配置

除了使用xml進行配置,還可以使用注解配置,在Bean類上使用注解@Component注解,value屬性指定當前Bean實例的beanName,也可以省略不寫,不寫的情況下為當前類名首字母小寫。

需要在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"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 告知Spring框架去itheima包及其子包下去掃描使用了注解的類 --><context:component-scan base-package="com.itheima"/>
</beans>
//獲取方式:applicationContext.getBean("userDao");
@Component("userDao")
public class UserDaoImpl implements UserDao {
}
//獲取方式:applicationContext.getBean("userDaoImpl");
@Component
public class UserDaoImpl implements UserDao {
}

xml配置和注解的對應

image-20250404161156416

為了每層Bean標識的注解語義化更加明確,@Component又衍生出如下三個注解

image-20250404161317455

(8)Spring配置其他注解

@Primary注解用于標注相同類型的Bean優先被使用權,@Primary 是Spring3.0引入的,與@Component和@Bean一起使用,標注該Bean的優先級更高,則在通過類型獲取Bean或通過@Autowired根據類型進行注入時,會選用優先級更高的

注解 @Profile 標注在類或方法上,標注當前產生的Bean從屬于哪個環境,只有激活了當前環境,被標注的Bean才能被注冊到Spring容器里,不指定環境的Bean,任何環境下都能注冊到Spring容器里

2.Spring的get方法

image-20250404144908661

3.Spring配置非自定義Bean(第三方提供的Bean)

配置非自定義的Bean需要考慮如下兩個問題:

  • 被配置的Bean的實例化方式是什么?無參構造、有參構造、靜態工廠方式還是實例工廠方式;
  • 被配置的Bean是否需要注入必要屬性。

以MyBatis為例

原始代碼

//加載mybatis核心配置文件,使用Spring靜態工廠方式
InputStream in = Resources.getResourceAsStream(“mybatis-conifg.xml”);
//創建SqlSessionFactoryBuilder對象,使用Spring無參構造方式
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//調用SqlSessionFactoryBuilder的build方法,使用Spring實例工廠方式
SqlSessionFactory sqlSessionFactory = builder.build(in);

用xml配置

<!--靜態工廠方式產生Bean實例-->
<bean id=“inputStream” class=“org.apache.ibatis.io.Resources” factory-method=“getResourceAsStream”><constructor-arg name=“resource” value=“mybatis-config.xml/>
</bean>
<!--無參構造方式產生Bean實例-->
<bean id="sqlSessionFactoryBuilder" class="org.apache.ibatis.session.SqlSessionFactoryBuilder"/>
<!--實例工廠方式產生Bean實例-->
<bean id="sqlSessionFactory" factory-bean="sqlSessionFactoryBuilder" factory-method="build"><constructor-arg name="inputStream" ref="inputStream"/>
</bean>

用注解配置

//將方法返回值Bean實例以@Bean注解指定的名稱存儲到Spring容器中
@Bean("dataSource")
public DataSource dataSource(){DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName("com.mysql.jdbc.Driver");dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis");dataSource.setUsername("root");dataSource.setPassword("root");return dataSource;
}

工廠方法所在類必須要被Spring管理

如果需要注入參數的話,@Autowired可以省略

@Bean
@Autowired //根據類型匹配參數
public Object objectDemo01(UserDao userDao){System.out.println(userDao);return new Object();
}
@Bean
public Object objectDemo02(@Qualifier("userDao") UserDao userDao,
@Value("${jdbc.username}") String username){System.out.println(userDao);System.out.println(username);return new Object();
}

4.Bean實例化的基本流程

Spring容器在進行初始化時,會將xml配置的的信息封裝成一個BeanDefinition對象,所有的BeanDefinition存儲到一個名為beanDefinitionMap的Map集合中去,Spring框架在對該Map進行遍歷,使用反射創建Bean實例對象,創建好的Bean對象存儲在一個名為singletonObjects的Map集合中,當調用getBean方法時則最終從該Map集合中取出Bean實例對象返回。

image-20250404145336228

5.Spring的后處理器

Spring的后處理器是Spring對外開發的重要擴展點,允許我們介入到Bean的整個實例化流程中來,以達到動態注冊BeanDefinition,動態修改BeanDefinition,以及動態修改Bean的作用。Spring主要有兩種后處理器:

  • BeanFactoryPostProcessor:Bean工廠后處理器,在BeanDefinitionMap填充完畢,Bean實例化之前執行;

    BeanFactoryPostProcessor是一個接口規范,實現了該接口的類只要交由Spring容器(xml文件中用bean配置)管理的話,那么Spring就會回調該接口的方法,用于對BeanDefinition注冊和修改的功能。

    public interface BeanFactoryPostProcessor {void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory);
    }
    

    可以動態修改BeanDefinition(修改class,修改初始化方法,是否懶加載)

    Spring 提供了一個BeanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor專門用于注冊BeanDefinition操作

    public class MyBeanFactoryPostProcessor2 implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {}@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {BeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName("com.itheima.dao.UserDaoImpl2");beanDefinitionRegistry.registerBeanDefinition("userDao2",beanDefinition);}
    }
    

    這個對象本身也會交給spring容器管理,進入到單例池中

  • BeanPostProcessor:Bean后處理器,一般在Bean實例化之后,填充到單例池singletonObjects之前執行。

    Bean被實例化后,到最終緩存到名為singletonObjects單例池之前,中間會經過Bean的初始化過程,例如:屬性的填充、初始方法init的執行等,其中有一個對外進行擴展的點BeanPostProcessor,我們稱為Bean后處理

    public interface BeanPostProcessor {@Nullable//在屬性注入完畢,init初始化方法執行之前被回調default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Nullable//在初始化方法執行之后,被添加到單例池singletonObjects之前被回調default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
    }
    

    這個對象本身也會交給spring容器管理,進入到單例池中

    image-20250404150933106

image-20250404150943323

6.Spring的生命周期

Spring Bean的生命周期是從 Bean 實例化之后,即通過反射創建出對象之后,到Bean成為一個完整對象,最終存儲到單例池中,這個過程被稱為Spring Bean的生命周期。Spring Bean的生命周期大體上分為三個階段:

  • Bean的實例化階段:Spring框架會取出BeanDefinition的信息進行判斷當前Bean的范圍是否是singleton的,是否不是延遲加載的,是否不是FactoryBean等,最終將一個普通的singleton的Bean通過反射進行實例化;
  • Bean的初始化階段:Bean創建之后還僅僅是個"半成品",還需要對Bean實例的屬性進行填充、執行一些Aware接口方法、執行BeanPostProcessor方法、執行InitializingBean接口的初始化方法、執行自定義初始化init方法等。該階段是Spring最具技術含量和復雜度的階段,Aop增強功能,后面要學習的Spring的注解功能等、spring高頻面試題Bean的循環引用問題都是在這個階段體現的;
  • Bean的完成階段:經過初始化階段,Bean就成為了一個完整的Spring Bean,被存儲到單例池singletonObjects中去了,即完成了Spring Bean的整個生命周期。

初始化階段主要設計以下幾個過程:

  • Bean實例的屬性填充
  • Aware接口屬性注入
  • BeanPostProcessor的before()方法回調
  • InitializingBean接口的初始化方法回調
  • 自定義初始化方法init回調
  • BeanPostProcessor的after()方法回調

(1)Bean的實例屬性填充

Spring在進行屬性注入時,會分為如下幾種情況:

  • 注入普通屬性,String、int或存儲基本類型的集合時,直接通過set方法的反射設置進去;

  • 注入單向對象引用屬性時,從容器中getBean獲取后通過set方法反射設置進去,如果容器中沒有,則先創建被注入對象Bean實例(完成整個生命周期)后,在進行注入操作;

  • 注入雙向對象引用屬性時,就比較復雜了,涉及了循環引用(循環依賴)問題,下面會詳細闡述解決方案

    image-20250404151853826

三級緩存

public class DefaultSingletonBeanRegistry ... {//1、最終存儲單例Bean成品的容器,即實例化和初始化都完成的Bean,稱之為"一級緩存"Map<String, Object> singletonObjects = new ConcurrentHashMap(256);//2、早期Bean單例池,緩存半成品對象,且當前對象已經被其他對象引用了,稱之為"二級緩存"Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);//3、單例Bean的工廠池,緩存半成品對象,對象未被引用,使用時在通過工廠創建Bean,稱之為"三級緩存"Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
}

UserService和UserDao循環依賴的過程結合上述三級緩存描述一下

  • UserService 實例化對象,但尚未初始化,將UserService存儲到三級緩存
  • UserService 屬性注入,需要UserDao,從緩存中獲取,沒有UserDao;
  • UserDao實例化對象,但尚未初始化,將UserDao存儲到到三級緩存
  • UserDao屬性注入,需要UserService,從三級緩存獲取UserService,UserService從三級緩存移入二級緩存
  • UserDao執行其他生命周期過程,最終成為一個完成Bean,存儲到一級緩存,刪除二三級緩存
  • UserService 注入UserDao;
  • UserService執行其他生命周期過程,最終成為一個完成Bean,存儲到一級緩存,刪除二三級緩存

(2)Aware接口

Aware接口是一種框架輔助屬性注入的一種思想,其他框架中也可以看到類似的接口。框架具備高度封裝性,我們接觸到的一般都是業務代碼,一個底層功能API不能輕易的獲取到,但是這不意味著永遠用不到這些對象,如果用到了,就可以使用框架提供的類似Aware的接口,讓框架給我們注入該對象。

image-20250404152143059

image-20250404152209620

7.整合第三方框架(如何使用第三方功能)

(1)使用默認命名空間 beans

Spring整合MyBatis的步驟如下:

原始代碼

public static void main(String[] args) throws IOException {// 加載 MyBatis 配置文件String resource = "com/example/config/mybatis-config.xml";Reader reader = Resources.getResourceAsReader(resource);// 構建 SqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);// 打開 SqlSessiontry (SqlSession session = sqlSessionFactory.openSession()) {// 獲取 MapperUserMapper userMapper = session.getMapper(UserMapper.class);// 查詢用戶User user = userMapper.selectUserById(1);System.out.println("User: " + user.getUsername() + ", Password: " + user.getPassword());// 插入用戶User newUser = new User();newUser.setUsername("newuser");newUser.setPassword("newpassword");userMapper.insertUser(newUser);session.commit(); // 提交事務}}
  • 導入MyBatis整合Spring的相關坐標;

  • 編寫Mapper和Mapper.xml;

  • 配置SqlSessionFactoryBean和MapperScannerConfigurer;

    <!--配置數據源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="url" value="jdbc:mysql://localhost:3306/mybatis"></property><property name="username" value="root"></property><property name="password" value="root"></property>
    </bean>
    <!--配置SqlSessionFactoryBean-->
    <bean class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--配置Mapper包掃描-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.itheima.dao"></property>
    </bean>
    
  • 編寫測試代碼

原理(對照原始代碼看)

  • SqlSessionFactoryBean:實現了FactoryBean規范,用于提供SqlSessionFactory;用于創建SqlSession

  • MapperScannerConfigurer:實現了BeanDefinitionRegistryPostProcessor接口,完成注冊,用于掃描指定包下的mapper注冊到BeanDefinitionMap中;

  • MapperFactoryBean:實現了FactoryBean規范,它的getObject方法就是this.getSqlSession().getMapper(this.mapperInterface);

  • ClassPathMapperScanner:在mapper(接口,無法實例化成一個對象)注冊到BeanDefinitionMap后,動態修改BeanDefinitionMap,對于每一個mapper的class修改成MapperFactoryBean

    definition.setAutowireMode(2) 修改了自動注入狀態(根據類型),所以MapperFactoryBean中的setSqlSessionFactory會自動注入進去。

使用注解整合

@Configuration
@ComponentScan("com.itheima")
@MapperScan("com.itheima.mapper")
public class ApplicationContextConfig {@Beanpublic DataSource dataSource(){DruidDataSource dataSource = new DruidDataSource();//省略部分代碼return dataSource;}@Beanpublic SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);return sqlSessionFactoryBean;
}}

@MapperScan不是Spring提供的注解,是MyBatis為了整合Spring,在整合包org.mybatis.spring.annotation中提供的注解。這個注解上有一個元注解,@Import({MapperScannerRegistrar.class}),當@MapperScan被掃描加載時,會解析@Import注解,從而加載指定的類,此處就是加載了MapperScannerRegistrar。

MapperScannerRegistrar實現了ImportBeanDefinitionRegistrar接口,Spring會自動調用registerBeanDefinitions方法,該方法中又注冊MapperScannerConfigurer類,而MapperScannerConfigurer類作用是掃描Mapper,向容器中注冊Mapper對應的MapperFactoryBean

@Import注解

@Import可以導入如下三種類:

  • 普通的配置類

  • 實現ImportSelector接口的類

    重寫String[] selectImports(AnnotationMetadata annotationMetadata)方法,//返回要進行注冊的Bean的全限定名數組

  • 實現ImportBeanDefinitionRegistrar接口的類

    重寫registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry),手動注冊BeanDefinition

(2)使用第三方命名空間(如何生效的)

需求:加載外部properties文件,將鍵值對存儲在Spring容器中

jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=root

引入context命名空間,在使用context命名空間的標簽,使用SpEL表達式在xml或注解中根據key獲得value

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:property-placeholder location="classpath:jdbc.properties" /><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean>
<beans>
  • 將自定義標簽的約束 與 物理約束文件與網絡約束名稱的約束 以鍵值對形式存儲到一個spring.schemas文件里,該文件存儲在類加載路徑的 META-INF里,Spring會自動加載到;

    http\://www.springframework.org/schema/context/spring-context.xsd=org/springframework/context/config/spring-context.xsd
    

    在xsd文件中就定義了命令空間下有哪些子標簽

  • 將自定義命名空間的名稱 與 自定義命名空間的處理器映射關系 以鍵值對形式存在到一個叫spring.handlers文件里,該文件存儲在類加載路徑的 META-INF里,Spring會自動加載到;

    http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
    
  • 在ContextNamespaceHandler中,會為命名空間中的每一個標簽都注冊一個解析器

    public class ContextNamespaceHandler extends NamespaceHandlerSupport {public ContextNamespaceHandler() {}public void init() {this.registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());this.registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());this.registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());this.registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());this.registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());this.registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());this.registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());}
    }
    

    根據標簽,找到對應的解析器進行解析

8.Spring注解的解析原理

(1)xml配置組件掃描

<context:component-scan base-package="com.itheima"/>

component-scan是一個context命名空間下的自定義標簽,所以要找到對應的命名空間處理器NamespaceHandler 和 解析器.

將ComponentScanBeanDefinitionParser進行了注冊

(2)配置類配置組件掃描

@Configuration
@ComponentScan("com.itheima")
public class AppConfig {
}

使用AnnotationConfigApplicationContext容器在進行創建時,內部調用了如下代碼,該工具注冊了幾個Bean后處理器

image-20250404163740206

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/74534.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/74534.shtml
英文地址,請注明出處:http://en.pswp.cn/web/74534.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

人工智能爬蟲導致維基共享資源帶寬需求激增 50%

2025 年 4 月 1 日&#xff0c;維基媒體基金會在博文中表示&#xff0c;自 2024 年 1 月以來&#xff0c;維基共享資源下載多媒體的帶寬消耗激增 50%&#xff0c;這一變化趨勢主要由用于 AI 訓練數據集的網絡爬蟲導致。以下是具體分析1&#xff1a; 爬蟲流量特征與數據存儲模式…

2007-2019年各省地方財政交通運輸支出數據

2007-2019年各省地方財政交通運輸支出數據 1、時間&#xff1a;2007-2019年 2、來源&#xff1a;國家統計局、統計年鑒 3、指標&#xff1a;行政區劃代碼、地區、年份、地方財政交通運輸支出 4、范圍&#xff1a;31省 5、指標說明&#xff1a;地方財政交通運輸支出是指地方…

【爬蟲開發】爬蟲開發從0到1全知識教程第14篇:scrapy爬蟲框架,介紹【附代碼文檔】

本教程的知識點為&#xff1a;爬蟲概要 爬蟲基礎 爬蟲概述 知識點&#xff1a; 1. 爬蟲的概念 requests模塊 requests模塊 知識點&#xff1a; 1. requests模塊介紹 1.1 requests模塊的作用&#xff1a; 數據提取概要 數據提取概述 知識點 1. 響應內容的分類 知識點&#xff1a…

【CMake】《CMake構建實戰:項目開發卷》筆記-Chapter8-生成器表達式

第8章 生成器表達式 生成器表達式&#xff08;generator expression&#xff09;是由CMake生成器進行解析的表達式&#xff0c;因此&#xff0c;這些表達式只有在CMake的生成階段才被解析為具體的值。 CMake在生成階段&#xff0c;能夠根據具體選用的構建系統生成器生成特定…

Docker安裝、配置Mysql5.7

1.創建必要的目錄 # 創建目錄 mkdir -p ~/docker/software/mysql/{conf,log,data} 2.如果沒有docker-compose.yml文件的話&#xff0c;先創建docker-compose.yml 配置文件一般長這個樣子 version: 3services:mysql:image: mysql:5.7.36container_name: mysqlports:- "…

【C++學習筆記】十三、速通筆記

完整的C編程教程 目錄 開發環境配置C知識體系現代C特性設計模式數據結構CMake項目構建調試技巧進階主題學習資源 1. 開發環境配置 1.1 安裝編譯器 sudo apt-get install g build-essential1.2 安裝構建工具 sudo apt-get install cmake1.3 VS Code配置 安裝C擴展配置調試…

網絡運維學習筆記(DeepSeek優化版)027 OSPF外部路由計算

文章目錄 OSPF外部路由計算1. 實驗拓撲與基礎配置2. 關鍵配置命令2.1 引入靜態路由2.2 查看路由表 3. LSA生成與傳播分析3.1 ASBR角色通告&#xff08;1類LSA&#xff09;3.2 外部路由通告&#xff08;5類LSA&#xff09;3.3 外部路由引入過程 4. 5類LSA關鍵字段解析5. 外部路由…

【Python使用】嘿馬推薦系統全知識和項目開發教程第2篇:1.4 案例--基于協同過濾的電影推薦,1.5 推薦系統評估【附代碼

教程總體簡介&#xff1a;1.1 推薦系統簡介 學習目標 1 推薦系統概念及產生背景 2 推薦系統的工作原理及作用 3 推薦系統和Web項目的區別 1.3 推薦算法 1 推薦模型構建流程 2 最經典的推薦算法&#xff1a;協同過濾推薦算法&#xff08;Collaborative Filtering&#xff09; 3 …

運算放大器(五)電壓比較器

比較器在最常用的簡單集成電路中排名第二&#xff0c;僅次于排名第一的運算放大器。 電壓比較器是一種用來比較輸入信號電壓與參考電壓大小&#xff0c;并將比較結果以高電平或低電平形式輸出的一種信號處理電路&#xff0c;廣泛應用于各種非正弦波的產生和變換電路中&#xf…

Java面試黃金寶典34

1. 主鍵索引底層的實現原理 定義 主鍵索引是數據庫中用于唯一標識表中每一行記錄的索引&#xff0c;常見的底層實現是 B 樹結構。B 樹是一種平衡的多路搜索樹&#xff0c;由內部節點和葉子節點組成。內部節點只存儲索引鍵和指向下一層節點的指針&#xff0c;不存儲實際數據&am…

Educational Codeforces Round 177 (Rated for Div. 2)

Educational Codeforces Round 177 (Rated for Div. 2) A. Cloudberry Jam 思路&#xff1a; 1千克果子能生產2/3千克果醬&#xff0c;生產3千克果醬則需要2千克果醬&#xff0c;所以*2即可 code: void solve() { int x; cin >> x;cout << 2 * x << e…

ARM-外部中斷,ADC模數轉換器

根據您提供的圖片&#xff0c;我們可以看到一個S3C2440微控制器的中斷處理流程圖。這個流程圖展示了從中斷請求源到CPU的整個中斷處理過程。以下是流程圖中各個部分與您提供的寄存器之間的關系&#xff1a; 請求源&#xff08;帶sub寄存器&#xff09;&#xff1a; 這些是具體的…

23種設計模式-行為型模式-迭代器

文章目錄 簡介問題解決代碼設計關鍵點&#xff1a; 總結 簡介 迭代器是一種行為設計模式&#xff0c;讓你能在不暴露集合底層表現形式(列表、棧和樹等)的情況下遍歷集合中所有的元素。 問題 集合是編程中最常使用的數據類型之一。 大部分集合使用簡單列表存儲元素。但有些集…

Python 布爾類型

Python 布爾類型(Boolean) 布爾類型是Python中的基本數據類型之一&#xff0c;用于表示邏輯值。它只有兩個值&#xff1a; True - 表示真False - 表示假 1. 布爾值的基本使用 # 定義布爾變量 is_active True is_admin Falseprint(is_active) # 輸出: True print(is_admi…

人工智能在前端開發中的應用探索

一、人工智能在前端開發中的應用場景 人工智能&#xff08;AI&#xff09;技術的快速發展為前端開發帶來了新的機遇和挑戰。AI在前端開發中的應用主要集中在以下幾個方面&#xff1a;智能代碼生成、自動化測試、個性化推薦、智能交互設計以及性能優化。這些應用場景不僅提高了…

三維掃描助力文化遺產數字化保護

當下&#xff0c;三維掃描技術以其獨特的優勢&#xff0c;正逐漸成為文化遺產數字化保護的重要工具&#xff0c;讓珍貴的文物得以“永生”。 三維掃描在文物數字化方面的應用&#xff1a; 高精度文物存檔&#xff1a;三維掃描技術能夠實現對文物的快速、無損掃描&#xff0c;…

如何將生活場景轉換為數據模型模型仿真?

從家到公司有31公里&#xff0c;其中有一個2車道右轉立交橋匯入另外一條路&#xff0c;每次都是那個堵車&#xff0c;導致路上的行程在45分鐘到70分鐘左右&#xff1f;前面或后面路段都是3-4車道&#xff0c;足夠通行。如何解決這個難題&#xff0c;是否可搭建數學模型實現可視…

Java學習總結-io流-練習案例

將文檔的內容排序&#xff1a; public static void main(String[] args) throws IOException {File dir new File("J:\\360downloads\\wpcache\\srvsetwp\\xxx\\test.txt");BufferedReader br new BufferedReader(new FileReader(dir));//把按行讀取到的內容&#…

【C++】STL庫_stack_queue 的模擬實現

棧&#xff08;Stack&#xff09;、隊列&#xff08;Queue&#xff09;是C STL中的經典容器適配器 容器適配器特性 不是獨立容器&#xff0c;依賴底層容器&#xff08;deque/vector/list&#xff09;通過限制基礎容器接口實現特定訪問模式不支持迭代器操作&#xff08;無法遍歷…

LangChain核心解析:掌握AI開發的“鏈“式思維

0. 思維導圖 1. 引言 ?? 在人工智能快速發展的今天,如何有效地利用大語言模型(LLM)構建強大的應用成為眾多開發者關注的焦點。前面的課程中,我們學習了正則表達式以及向量數據庫的相關知識,了解了如何處理文檔并將其附加給大模型。本章我們將深入探討LangChain中的核心概…