知識點梳理
課堂講義
1)注解驅動的意義
1.1)什么是注解驅動
使用注解的形式替代xml配置,將繁雜的配置文件從工程中徹底消除掉,簡化書寫,提高開發效率
1.2)注解驅動的弊端
-
為了達成注解驅動的目的,可能會將原先很簡單的書寫,變的更加復雜
-
XML中配置第三方開發的資源是很方便的,但使用注解驅動無法在第三方開發的資源中進行編輯,因此會增加一部分的代碼量
2)常用注解(重點)
2.1)啟動注解功能
-
啟動注解掃描,加載類中配置的注解項
<!--注解總開關-->
<context:component-scan base-package="com.itheima"/> -
說明:
-
在進行包所掃描時,會對配置的包及其子包中所有文件進行掃描
-
掃描過程是以文件夾遞歸迭代的形式進行的
-
掃描過程僅讀取合法的java文件
-
掃描時僅讀取spring可識別的注解
-
掃描結束后會將可識別的有效注解轉化為spring對應的資源加入IoC容器
-
-
注意:
-
無論是注解格式還是XML配置格式,最終都是將資源加載到IoC容器中,差別僅僅是數據讀取方式不同
-
從開發效率上來說注解優於XML配置文件
-
2.2)bean的定義
-
名稱:@Component
-
類型:類注解
-
位置:類定義上方
-
作用:設置該類為spring管理的bean
-
范例:
-
說明:@Component的衍生注解,功能類似@Component
-
@Controller(表現層)
-
@Service(業務層)
-
@Repository(數據層)
-
-
相關屬性
-
value(默認):定義bean的訪問id
-
2.3)bean的作用域
-
名稱:@Scope
-
類型:類注解
-
位置:類定義上方
-
作用:設置該類作為bean對應的scope屬性
-
范例:
-
相關屬性
-
value(默認):定義bean的作用域singleton、prototype,默認為singleton
-
2.4)bean的生命周期
-
名稱:@PostConstruct、@PreDestroy
-
類型:方法注解
-
位置:方法定義上方
-
作用:設置該類作為bean對應的生命周期方法
-
范例:
小結
-
開啟注解驅動:
<context:component-scan base-package="com.itheima"/>
-
bean的四種注解定義格式:Component, Controller, Service, Repository
-
bean相關屬性注解格式:Scope, PostConstruct(方法上), PreDestroy(方法上)
2.5)加載第三方資源
-
名稱:@Bean
-
類型:方法注解
-
位置:方法定義上方
-
作用:設置該方法的返回值作為spring管理的bean
-
范例:
-
說明:
-
因為第三方bean無法在其源碼上進行修改,使用@Bean解決第三方bean的引入問題
-
該注解用於替代XML配置中的靜態工廠與實例工廠創建bean,不區分方法是否為靜態或非靜態
-
@Bean所在的類必須被spring掃描加載,否則該注解無法生效
-
-
相關屬性
-
value(默認):定義bean的訪問id
-
2.6)bean的非引用類型屬性注入
-
名稱:@Value
-
類型:屬性注解、方法注解
-
位置:屬性定義上方,set方法定義上方
-
作用:設置對應屬性的值或對方法進行傳參
-
范例:
@Value("zhangsan") private String username;
-
說明:
-
value值僅支持非引用類型數據
-
value值支持SpEL:
@Value("#{'zhangsan'}")
-
@value注解如果添加在屬性上方,可以省略set方法
-
value值支持讀取properties文件中的屬性值,通過類屬性將properties中數據傳入類中
-
-
相關屬性
-
value(默認):定義對應的屬性值或參數值
-
2.7)bean的引用類型屬性注入
-
名稱:@Autowired、@Qualifier
-
類型:屬性注解、方法注解
-
位置:屬性定義上方,方法定義上方
-
作用:設置對應屬性的對象或對方法進行引用類型傳參
-
范例:
-
說明:
-
@Autowired默認按類型裝配
-
指定@Qualifier后可以指定自動裝配的bean的id
@Autowired @Qualifier("userDao") private UserDao userDao;
-
-
相關屬性
-
required:定義該屬性是否允許為null
-
2.8)bean裝配優先級配置
-
名稱:@Primary
-
類型:類注解
-
位置:類定義上方
-
作用:設置類對應的bean按類型裝配時優先裝配
-
范例:
@Component @Primary public class ClassName{}
-
說明:
@Autowired默認按類型裝配,當出現相同類型的bean,使用@Primary提高按類型自動裝配的優先級,多個@Primary會導致優先級設置無效
2.9)bean的引用類型屬性原生注解注入(了解)
-
名稱:@Inject、@Named、@Resource
-
說明:
-
@Inject與@Named是JSR330規范中的注解
-
@Inject = @Autowired ,@Named = @Qualifier完全相同
-
-
@Resource是JSR250規范中的注解,可以簡化書寫格式
-
@Resource相關屬性
-
name:設置注入的bean的id
-
type:設置注入的bean的類型,接收的參數為Class類型
-
小結
屬性注入
-
非引用類型注入:@Value
-
引用類型注入
-
@Autowired = @Inject
-
@Qualifier = @Named
-
@Primary
-
@Resource: name, type
-
2.10)加載properties文件
-
名稱:@PropertySource
-
類型:類注解
-
位置:類定義上方
-
作用:加載properties文件中的屬性值
-
范例:
-
說明:
-
不支持*通配格式
-
一旦加載,所有spring控制的bean中均可使用對應屬性值
-
-
相關屬性
-
value(默認):設置加載的properties文件名
-
ignoreResourceNotFound:如果資源未找到,是否忽略,默認為false
-
2.11)純注解格式
-
名稱:@Configuration、@ComponentScan
-
類型:類注解
-
位置:類定義上方
-
作用:設置當前類為spring核心配置加載類
-
范例:
@Configuration @ComponentScan("scanPackageName") public class SpringConfigClassName{ }
-
說明:
-
核心配合類用於替換spring核心配置文件,此類可以設置空的,不設置變量與屬性
-
bean掃描工作使用注解@ComponentScan替代
-
AnnotationConfigApplicationContext
-
加載純注解格式上下文對象,需要使用AnnotationConfigApplicationContext
-
當配置類作為 AnnotationConfigApplicationContext 對象創建的參數時,@Configuration注解可以不寫
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
2.12)第三方bean配置與管理
-
名稱:@Import
-
類型:類注解
-
位置:類定義上方
-
作用:導入第三方bean作為spring控制的資源
-
范例:
@Configuration @Import(OtherClassName.class) public class ClassName { }
-
說明:
-
@Import注解在同一個類上,僅允許添加一次,如果需要導入多個,使用數組的形式進行設定
-
@Bean所在的類可以使用導入的形式進入spring容器,無需使用@Component聲明
-
在被導入的類中可以繼續使用@Import導入其他資源(了解)
-
小結
-
屬性注入:Value, Autowired, Qualifier, Primary, Inject, Named, Resource
-
加載properties文件:PropertySource -> Value("${key}")
-
純注解:Configuration, ComponenScan
-
第三方導入:Import
3)bean加載控制(了解)
3.1)依賴加載
(1)@DependsOn
-
名稱:@DependsOn
-
類型:類注解、方法注解
-
位置:bean定義的位置(類上或方法上)
-
作用:控制bean的加載順序,使其在指定bean加載完畢后再加載
-
范例:
@DependsOn("beanId") public class ClassName { }
-
說明:
-
配置在方法上,使@DependsOn指定的bean優先於@Bean注解配置的bean進行加載
-
配置在類上,使@DependsOn指定的bean優先於當前類中所有@Bean配置的bean進行加載
-
配置在類上,使@DependsOn指定的bean優先於@Component等配置的bean進行加載
-
-
相關屬性
-
value(默認):設置當前bean所依賴的bean的id
-
(2)@Order
-
名稱:@Order
-
類型:配置類注解
-
位置:配置類定義的位置(類上)
-
作用:控制配置類的加載順序,其中值越小優先級越高
-
范例:
@Order(1) public class SpringConfigClassName { }
(3)@Lazy
-
名稱:@Lazy
-
類型:類注解、方法注解
-
位置:bean定義的位置(類上或方法上)
-
作用:控制bean的加載時機,使其延遲加載
-
范例:
@Lazy public class ClassName { }
3.2)依賴加載應用場景
@DependsOn
-
微信訂閱號,發布消息和訂閱消息的bean的加載順序控制
@Lazy
-
某個業務災難出現后對應的應急預案處理bean可以延遲加載
@Order
-
多個種類的配置出現后,優先加載系統級的,然后加載業務級的
4)整合第三方技術(重點)
4.1)注解整合MyBatis分析
-
業務類使用注解形式聲明bean,屬性采用注解注入
-
建立獨立的配置管理類,分類管理外部資源,根據功能進行分類,並提供對應的方法獲取bean
-
使用注解形式啟動bean掃描,加載所有注解配置的資源(bean)
-
使用AnnotationConfigApplicationContext對象加載所有的啟動配置類,內部使用導入方式進行關聯
4.2)注解整合MyBatis步驟
1.修改mybatis外部配置文件格式為注解格式
public interface AccountDao {
2.業務類使用@Service聲明bean,使用@Autowired注入對象
3.編寫Spring配置類:SpringConfig,並加載properties文件
@Configuration @PropertySource("classpath:jdbc.properties") public class SpringConfig { }
4.建立配置文件JDBCConfig與MyBatisConfig類,並將其導入到核心配置類SpringConfig
數據源配置類:JDBCConfig
public class JDBCConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String userName; @Value("${jdbc.password}") private String password; @Bean(value = "dataSource") public DataSource getDataSource(){ DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(userName); ds.setPassword(password); return ds; } }
MyBatis配置類:MyBatisConfig
public class MyBatisConfig { @Bean public SqlSessionFactoryBean getSqlSessionFactoryBean(@Autowired DataSource dataSource){ SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean(); ssfb.setTypeAliasesPackage("com.itheima.domain"); ssfb.setDataSource(dataSource); return ssfb; } @Bean public MapperScannerConfigurer getMapperScannerConfigurer(){ MapperScannerConfigurer msc = new MapperScannerConfigurer(); msc.setBasePackage("com.itheima.dao"); return msc; } }
5.開啟注解掃描,將JDBCConfig與MyBatisConfig類導入到核心配置類SpringConfig中
@Configuration @ComponentScan("com.itheima") @PropertySource("classpath:jdbc.properties") @Import({JDBCConfig.class,MyBatisConfig.class}) public class SpringConfig { }
6.使用AnnotationConfigApplicationContext對象加載配置項
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
AccountService accountService = (AccountService) ctx.getBean("accountService");
Account ac = accountService.findById(3);
System.out.println(ac);
}
}
4.3)注解整合Junit
1.導入Spring整合Junit坐標,從Spring5.0以后,要求Junit的版本必須是4.12及以上
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
2.Spring接管Junit的運行權,使用Spring專用的Junit類加載器
@RunWith(SpringJUnit4ClassRunner.class)
3.加載Spring配置類
@ContextConfiguration(classes = SpringConfig.class)
5)IoC底層核心原理
5.1)IoC核心接口
查看類文件:Ctrl+n
查看類結構:Ctrl+h
查看內部結構:Alt+7
1.BeanFactory接口
2.HierarchicalBeanFactory接口
3.AutowireCapableBeanFactory接口
4.ListableBeanFactory
5.2)組件掃描器
-
開發過程中,需要根據需求加載必要的bean,排除指定bean
5.3)設定組件掃描加載過濾器
-
名稱:@ComponentScan
-
類型:類注解
-
位置:類定義上方
-
作用:設置spring配置加載類掃描規則
-
范例:
excludeFilters:設置排除性過濾器
includeFilters:設置包含性過濾器
type:設置過濾器類型:ANNOTATION, CUSTOM
5.4)自定義組件過濾器(了解)
-
名稱:TypeFilter
-
類型:接口
-
作用:自定義類型過濾器
-
編寫自定義過濾器
public class MyTypeFilter implements TypeFilter {
-
使用自定義過濾器:設置排除bean,排除的規則是自定義規則(FilterType.CUSTOM),具體的規則定義為(MyTypeFilter.class)
5.5)自定義導入器(了解)
1.回顧如何讓Spring管理bean
-
配置bean的方式如下:
-
XML文件中使用<bean />標簽配置
-
使用@Component及衍生注解配置
-
2.為什么需要使用自定義導入器
-
企業開發過程中,通常需要配置大量的bean,需要一種快速高效配置大量bean的方式
實現接口ImportSelector
-
名稱:ImportSelector
-
-
類型:接口
-
作用:自定義bean導入器
-
-
范例:
public class MyImportSelector implements ImportSelector { public String[] selectImports(AnnotationMetadata icm) { return new String[]{"com.itheima.dao.impl.AccountDaoImpl"}; } }
@Configuration @ComponentScan("com.itheima") @Import(MyImportSelector.class) public class SpringConfig { }
1.從properties文件讀取需要導入的單個類
public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { //2.加載import.properties文件中的單個類名 ResourceBundle bundle = ResourceBundle.getBundle("import"); String className = ,bundle.getString("className"); return new String[] {className}; } }
#2.加載import.properties文件中的單個類名 className=com.itheima.dao.impl.BookDaoImpl
2.從properties文件讀取需要導入的多個類
public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { // 3.加載import.properties文件中的多個類名 ResourceBundle bundle = ResourceBundle.getBundle("import"); String className = bundle.getString("className"); return className.split(","); } }
#3.加載import.properties文件中的多個類名 className=com.itheima.dao.impl.BookDaoImpl,com.itheima.dao.impl.AccountDaoImpl
3.從properties文件讀取需要導入的指定包下的所有類:使用自定義的CustomerImportSelector
path=com.itheima.dao.impl.*
5.6)自定義注冊器(了解)
-
名稱:ImportBeanDefinitionRegistrar
-
類型:接口
-
作用:自定義bean定義注冊器
-
范例:
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { public void registerBeanDefinitions(AnnotationMetadata icm, BeanDefinitionRegistry r) { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(r, false); TypeFilter tf = new TypeFilter() { public boolean match(MetadataReader mr, MetadataReaderFactory mrf) throws IOException { return true; } }; scanner.addIncludeFilter(tf); scanner.scan("com.itheima"); } }
5.7)bean初始化過程解析(理解)
-
BeanFactoryPostProcessor
-
作用:定義了在bean工廠對象創建后,bean對象創建前執行的動作,用於對工廠進行創建后業務處理
-
運行時機:當前操作用於對工廠進行處理,僅運行一次
public class MyBeanFactory implements BeanFactoryPostProcessor { @Override //工廠后處理bean接口核心操作 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { //第1階段 System.out.println("第1階段:采購手機屏幕和電池..."); } }
-
注意:導入自定義的MyBeanFactory
@Configuration @ComponentScan("com.itheima") @Import(MyBeanFactory.class) public class SpringConfig {...}
-
-
BeanPostProcessor
-
作用:定義了所有bean初始化前后進行的統一動作,用於對bean進行創建前業務處理與創建后業務處理
-
運行時機:當前操作伴隨着每個bean的創建過程,每次創建bean均運行該操作
public class MyBean implements BeanPostProcessor { //所有bean初始化前置操作 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { //第2階段 System.out.println(beanName); System.out.println("第2階段:檢查手機屏幕和電池是否正常"); return bean; } //所有bean初始化后置操作 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { //第4階段 System.out.println("第4階段:檢查手機功能是否正常"); return bean; } }
@Configuration @ComponentScan("com.itheima") @Import({MyBeanFactory.class, MyBean.class}) public class SpringConfig { }
-
-
InitializingBean
-
作用:定義了每個bean的初始化前進行的動作,屬於非統一性動作,用於對bean進行創建前業務處理
-
運行時機:當前操作伴隨着任意一個bean的創建過程,保障其個性化業務處理
@Service("mobileService") public class MobileServiceImpl implements MobileService, InitializingBean { @Override public void create() { System.out.println("手機要出廠啦..."); } @Override //定義當前bean初始化操作,功效等同於init-method屬性配置 public void afterPropertiesSet() { //第3階段 System.out.println("第3階段:購買紅外設備"); } }
-
5.8)繁瑣的bean初始化過程處理(了解)
-
舉例實現FactoryBean接口:MyBatis中的SqlSessionFactoryBean實現
對單一的bean的初始化過程進行封裝,達到簡化配置的目的:
public class EquipmentDaoImplFactoryBean implements FactoryBean {
獲取方式:
public class App {
public static void main(String[] args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(SpringConfig.class);
EquipmentDao equipmentDao = (EquipmentDao)ctx.getBean("equipmentDaoImplBean");
equipmentDao.save();
}
FactoryBean與BeanFactory區別
-
FactoryBean:封裝單個繁瑣bean的創建過程
-