沈陽(yáng)創(chuàng)新網(wǎng)站建設(shè)報(bào)價(jià)長(zhǎng)沙網(wǎng)站優(yōu)化公司
Spring學(xué)習(xí)筆記8 Bean的循環(huán)依賴問(wèn)題_biubiubiu0706的博客-CSDN博客
注解的存在主要是為了簡(jiǎn)化XML的配置.Spring6倡導(dǎo)全注解式開(kāi)發(fā)
回顧下
注解怎么定義,注解中的屬性怎么定義
注解怎么使用
通過(guò)反射機(jī)制怎么讀取注解
注解的自定義
注解的使用
通過(guò)反射機(jī)制怎么讀取注解
IOC之包掃描原理
需求:給定一個(gè)包名,掃描所有類,只要有@Component注解,就創(chuàng)建該類對(duì)象,然后放到Map集合中
Key為注解的value,Value為對(duì)象
bean包下新建
package com.example.client;import com.example.annotation.Component;import java.io.File;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;/*** 手寫(xiě)組件掃描* @author hrui* @date 2023/9/24 18:20*/
public class ComponentScan {public static void main(String[] args) throws Exception{//創(chuàng)建存放注解值的key和對(duì)象的容器Map<String,Object> beanMap=new HashMap<>();//目前只知道包名,掃描包下所有類,當(dāng)類上有@Component注解時(shí)候,實(shí)例化該對(duì)象,放到MapString packageName="com.example.bean";//開(kāi)始掃描//.這個(gè)正則表達(dá)式代表任意字符,這里的"."必須是一個(gè)普通的"."字符,不能是正則表達(dá)式中的"."String packagePath = packageName.replaceAll("\\.", "/");System.out.println(packagePath);URL url = ClassLoader.getSystemClassLoader().getResource(packagePath);String path = url.getPath();System.out.println(path);//獲取絕對(duì)路徑下所有文件File files=new File(path);File[] listFile = files.listFiles();Arrays.stream(listFile).forEach(f->{try {System.out.println(f.getName());System.out.println(f.getName().split("\\.")[0]);//拼接包名 獲得類名String className=packageName+"."+f.getName().split("\\.")[0];System.out.println(className);//通過(guò)反射機(jī)制解析注解Class<?> clazz = Class.forName(className);//判斷類上有沒(méi)有@Component注解if(clazz.isAnnotationPresent(Component.class)){//獲取注解Component annotation = clazz.getAnnotation(Component.class);String key=annotation.value();//有該注解就創(chuàng)建對(duì)象Object o = clazz.newInstance();beanMap.put(key, o);}} catch (Exception e) {e.printStackTrace();}});System.out.println(beanMap);}
}
上面就是包掃描的原理
聲明Bean的注解,常見(jiàn)的包括4個(gè)
@Compoent? ?組件
@Controller? ?控制器
@Service? ?業(yè)務(wù)
@Repository? ?DAO
新建模塊spring-010
pom.xml
<dependencies><!--Spring依賴--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.10</version></dependency><!--junit單元測(cè)試--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency><!--Log4j2依賴--><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.19.0</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.19.0</version></dependency> </dependencies>
引入日志文件,Spring默認(rèn)用的log4j2? ?在resources目錄下固定名稱log4j2.xml日志文件即可
<?xml version="1.0" encoding="UTF-8"?> <configuration><loggers><!--level指定?志級(jí)別,從低到?的優(yōu)先級(jí):ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF--><root level="INFO"><appender-ref ref="spring6log"/></root></loggers><appenders><!--輸出?志信息到控制臺(tái)--><console name="spring6log" target="SYSTEM_OUT"><!--控制?志輸出的格式--><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/></console></appenders> </configuration>
上面4個(gè)注解的源碼
@Component
看下@Controller? ?@Service? ?@Repository?
說(shuō)明@Component是老大? 一樣的效果
其實(shí)作用是一樣的,只為增加程序的可讀性
@Controller表示控制層? ? @Service表示業(yè)務(wù)層? ? @Repository表示持久層
那我非不想這么寫(xiě),都用@Component行不行,答案是:可以.你喜歡,你隨意
@Component? ?@Controller? @Service @Repository? 這4個(gè)常用的Spring注解如何使用
1.引入spring-context依賴--->里面的spring--aop依賴? ?這個(gè)已經(jīng)引入
2.在Spring配置文件中引入命名空間
3.配置包掃描
4.希望將對(duì)象交由Spring管理的類上加注解
測(cè)試
實(shí)際上,即使不取名,默認(rèn)也有名,類名首字母小寫(xiě)
將4個(gè)bean的注解里的vlaue去掉
例如
SpringIOC解決多個(gè)包掃描問(wèn)題
兩種解決方案:
1.在配置文件中指定多個(gè)包,用逗號(hào)隔開(kāi)
2.指定多個(gè)包的共同父包
測(cè)試
指定父包
SpringIOC注解式開(kāi)發(fā)之選擇性實(shí)例化Bean
例如某個(gè)包下有很多Bean,分別標(biāo)注了@Component? @Controller? @Service? @Repository
現(xiàn)在由于某種業(yè)務(wù)需要,允許@Controller注解的參與Bean管理,其他不實(shí)例化.
第一種解決方案
測(cè)試:只有A和C 創(chuàng)建對(duì)象了
第二種解決方案
負(fù)責(zé)注入的注解
@Component? @Controller? @Service? @Repository 這四個(gè)注解是用來(lái)聲明Bean的.
聲明后這些Bean交由Spring管理.
如何給Bean的屬性賦值,需要以下注解
@Value 用于注入簡(jiǎn)單類型? 可以用在屬性上? ?set方法上? ?構(gòu)造方法的形參上
@Autowired? 用于注入非簡(jiǎn)單類型? 用于 構(gòu)造方法上? ?方法上? 形參上? 屬性上? 注解上
@Qualifier
@Resource
@Value注解是專門用來(lái)注入簡(jiǎn)單類型的,專門用來(lái)代替
示例
現(xiàn)在不需要set方法
新建個(gè)配置文件
測(cè)試
再測(cè)一個(gè)
另外 @Value還可以用在set方法上
@Value還可以用在構(gòu)造方法中
再測(cè)
注意:這樣不行
SpringIOC注解之@Autowired和 @Qualifier
@Autowired注解可以用來(lái)注入非簡(jiǎn)單類型
單獨(dú)使用@Autowried注解.默認(rèn)根據(jù)類型匹配----->byType
如果要byName@Autowired和@Qualifier需要一起使用
注意:@Autowired單獨(dú)使用 都是byType
需要byName要和@Qualifier一起使用
另外建個(gè)包c(diǎn)om.example2
持久層接口
持久層實(shí)現(xiàn)類
業(yè)務(wù)層接口
業(yè)務(wù)層實(shí)現(xiàn)類
新建配置文件用以包掃描
測(cè)試
如果我接口下有多個(gè)實(shí)現(xiàn)類
就報(bào)錯(cuò)了? 原因 它找到兩個(gè)
需要@Autowired和@Qualifier聯(lián)合使用?
在Spring中,@Autowired
注解默認(rèn)會(huì)使用"byType"方式進(jìn)行自動(dòng)裝配,它會(huì)嘗試按照被注入的類型(數(shù)據(jù)類型)去尋找匹配的依賴,然后將依賴注入到目標(biāo)字段或方法參數(shù)中。如果存在多個(gè)匹配的依賴對(duì)象(同一類型的多個(gè)Bean),并且無(wú)法確定要注入哪一個(gè)時(shí),它會(huì)引發(fā)一個(gè)異常。
如果 "byType" 自動(dòng)裝配失敗,Spring 不會(huì)自動(dòng)嘗試 "byName" 自動(dòng)裝配。如果有多個(gè)相同類型的 Bean,但您希望顯式選擇其中一個(gè)進(jìn)行注入,您可以使用 @Qualifier
注解與 @Autowired
結(jié)合使用,以指定要注入的 Bean 的名稱
測(cè)試
下面演示@Autowired的可以自動(dòng)裝配的位置,@Autowired單獨(dú)使用時(shí),有兩個(gè)同類型的會(huì)報(bào)錯(cuò),
因此先把OrderDaoForMysql或者OrderDaoForOracle注釋掉一個(gè)
下面演示@Autowired的可以自動(dòng)裝配的位置
@Autowired在構(gòu)造方法上
測(cè)試
@Autowired在構(gòu)造方法參數(shù)上
測(cè)試
有給屬性賦值的構(gòu)造方法,省略掉@Autowired行不行 (注意:這里要求構(gòu)造方法必須只有一個(gè),且該構(gòu)造方法給屬性賦值)
測(cè)試
@Autowired放在set方法上
關(guān)于@Resource注解
@Resource注解也可以完成非簡(jiǎn)單類型注入.它和@Autowired的區(qū)別是
1.@Resource是JDK擴(kuò)展包中的注解,是javaEE的.更具通用性
2.@Autowired注解是Spring框架自己的
3.@Resource注解默認(rèn)byName,為指定名字使用屬性名為name.通過(guò)name找不到會(huì)自動(dòng)啟用byType裝配
4.@Autowired默認(rèn)byType,找不到的話不會(huì)自動(dòng)用byName,需要通過(guò)@Qualifier來(lái)byName
5.@Resource注解用在屬性上,set方法上
6.@Autowired注解用在屬性上,set方法上,構(gòu)造方法上,構(gòu)造方法參數(shù)上
@Resource注解屬于JDK擴(kuò)展包(如果是JDK8不需要額外引入依賴,高于JDK11或低于JDK8需要額外引入依賴)
注意:Spring6開(kāi)始不再支持JAVAEE,它支持JAKARTA9(需要引入依賴)
如果用的Spring6的引依賴
<dependency><groupId>jakarta.annotation</groupId><artifactId>jakarta.annotation-api</artifactId><version>2.1.1</version> </dependency>
如果用的Spring5?
<dependency><groupId>javax.annotation</groupId><artifactId>javax.annotation-api</artifactId><version>1.3.2</version> </dependency>
?
這用的Spring6? 引入依賴
新建個(gè)包
持久層接口
持久層實(shí)現(xiàn)類
業(yè)務(wù)層
新建配置文件包掃描
測(cè)試
測(cè)試放在set方法上
測(cè)試
@Resource不能放在構(gòu)造方法上
@Resource(name="xxxxx")如果不指定名字? 單寫(xiě)個(gè)@Resource會(huì)將屬性名作為名字,如果找不到bean,會(huì)用byType
如果
SpringIOC全注解開(kāi)發(fā)? 將Spring配置文件干掉