spring6注解式開發(fā)示例詳解
spring框架創(chuàng)建bean就是利用反射機(jī)制
反射機(jī)制的代碼如下:
public static void main(String[] args) throws Exception {
System.out.println("Hello, World!");
// 使用反射機(jī)制調(diào)用方法
// 獲取類
Class<?> clazz = Class.forName("com.ali.bean2.SomeService");
// 獲取方法
Method method = clazz.getMethod("doSomething", String.class, int.class);
// 獲取對(duì)象
Object obj = clazz.newInstance();
// 方法調(diào)用
// obj: 哪個(gè)對(duì)象調(diào)用這個(gè)方法
// "hello", 42: 方法參數(shù)
// hello: 方法的返回值
Object hello = method.invoke(obj, "hello", 42);
}spring IoC注解式開發(fā)
注解主要是為了簡(jiǎn)化xml配置。
注解怎么定義
新建Java Class 時(shí)選擇Annoation 類型的文件,這樣就創(chuàng)建了一個(gè)新的注解
// 自定義注解
// @Target 標(biāo)注注解的注解,叫做元注解
// ElementType.TYPE: 表示可以標(biāo)注在類上
// ElementType.FIELD: 表示可以標(biāo)注在屬性上
// 使用某個(gè)注解的時(shí)候,如果注解的屬性名是value,可以省略屬性名
// 使用某個(gè)注解的時(shí)候,如果注解的屬性值是數(shù)組,并且數(shù)組中只有一個(gè)值,可以省略大括號(hào)
@Target(value = {ElementType.TYPE,ElementType.FIELD})
// @Retention 標(biāo)注注解的生命周期,叫做元注解,表示最終保留在class文件中,并且可以被反射機(jī)制讀取
// RetentionPolicy.SOURCE: 注解只在源碼中存在,編譯成字節(jié)碼后就不存在了
// RetentionPolicy.CLASS: 注解在源碼和字節(jié)碼中都存在,運(yùn)行時(shí)不存在(默認(rèn)值),也就是不能被反射機(jī)制讀取
// RetentionPolicy.RUNTIME: 注解在源碼、字節(jié)碼和運(yùn)行時(shí)都存在
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
String value();
}怎么通過(guò)反射機(jī)制讀取注解
假設(shè)user類被注解@Component修飾
@Component("userBean")
public class User {
}public static void main(String[] args) throws Exception {
// 使用反射機(jī)制讀取注解
// 獲取類
Class<?> userClazz = Class.forName("com.ali.component.User");
// 判斷類上是否有某個(gè)注解
boolean hasAnnotation = userClazz.isAnnotationPresent(Component.class);
if (hasAnnotation) {
// 獲取類上的注解對(duì)象
Component component = userClazz.getAnnotation(Component.class);
// 訪問(wèn)注解的屬性
System.out.println("component value: " + component.value());
}
}組件掃描原理
主要是通過(guò)反射機(jī)制實(shí)例化注解標(biāo)記的類的對(duì)象。
public static void main(String[] args) {
// 根據(jù)一個(gè)包名,掃描這個(gè)包下面的所有類,當(dāng)這個(gè)類有@Component注解時(shí),實(shí)例化這個(gè)類,key是@Component注解的value,value是實(shí)例化的對(duì)象
String packageName = "com.ali.component";
// 將包名中的“.”替換成“/”
String path = packageName.replaceAll("\\.", "/");
// 包是在系統(tǒng)恨路徑下的一個(gè)目錄。獲取它的絕對(duì)路徑
String absolutePath = ClassLoader.getSystemClassLoader().getResource(path).getPath();
// 獲取包下面的所有類文件
File dir = new File(absolutePath);
File[] files = dir.listFiles();
Arrays.stream(files).forEach(file -> {
// 獲取類名
String classname = packageName + "." + file.getName().replace(".class", "");
// 通過(guò)反射機(jī)制解析注解
try {
Class<?> clazz = Class.forName(classname);
// 判斷類上是否有某個(gè)注解
boolean hasAnnotation = clazz.isAnnotationPresent(Component.class);
if (hasAnnotation) {
// 獲取類上的注解對(duì)象
Component component = clazz.getAnnotation(Component.class);
// 訪問(wèn)注解的屬性
System.out.println("component value: " + component.value());
// 實(shí)例化這個(gè)類
Object obj = clazz.getDeclaredConstructor().newInstance();
System.out.println("實(shí)例化對(duì)象: " + obj);
}
} catch (Exception e) {
e.printStackTrace();
}
});
}聲明bean的注解
聲明bean的注解有:@Component 、@Controller、 @Service 、@Repository。
實(shí)際上 @Controller @Service @Repository 這3個(gè)都是@Component 的別名,本質(zhì)上就是一個(gè)注解。主要是為了增強(qiáng)代碼的可讀性。
當(dāng)這4個(gè)注解標(biāo)注在類上是,如果沒(méi)有指定value值(也就是沒(méi)有指定bean名稱),那么bean名稱默認(rèn)成類名的首字母小寫。
選擇性實(shí)例化bean
假如有一個(gè)需求:只需要@Controller參與bean的管理。其他三個(gè)注解都不參與實(shí)例化,這種情況要怎么處理?
注意:別忘了添加配置文件的命名空間。
<!-- 第一種方案:使用@ComponentScan自動(dòng)掃描bean
use-default-filters="false" 表示不使用默認(rèn)的過(guò)濾器(即所有聲明bean的注解全部失效)
@Component 、@Controller、 @Service 、@Repository 全部失效-->
<context:component-scan base-package="com.ali.bean2" use-default-filters="false">
<!-- 自定義過(guò)濾器,指定只掃描帶有@Component注解的類
只有@Component生效-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
<!-- 如果想讓@Service生效,可以添加下面這一行-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
<!-- 第二種方案:use-default-filters="true" 或者不寫該屬性,表示 @Component 、@Controller、 @Service 、@Repository 全部生效-->
<context:component-scan base-package="com.ali.bean2" >
<!-- 排除@Controller注解的類
只有@Controller生效-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<!-- 如果想讓@Repository失效,可以添加下面這一行-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>負(fù)責(zé)注入的注解
@value
@value:使用@value注入的話,屬性可以不提供setter方法,負(fù)責(zé)注入簡(jiǎn)單類型。
public class User {
@Value("Alice")
private String name;
@Value("22")
private int age;
}@value注解也可以加在setter方法上
public class User {
private String name;
private int age;
@Value("Alice")
public void setName(String name) {
this.name = name;
}
@Value("22")
public void setAge(int age) {
this.age = age;
}
}@value注解也可以加在構(gòu)造方法上
public class User {
private String name;
private int age;
public User(@Value("Alice") String name,@Value("22") int age) {
this.name = name;
this.age = age;
}
}@Autowired
@Autowired可以用來(lái)注入非簡(jiǎn)單類型,翻譯為:自動(dòng)裝配。
單獨(dú)使用 @Autowired注解,默認(rèn)根據(jù)類型裝配【默認(rèn)是byType】
注意:假如一個(gè)接口被2個(gè)或以上的類實(shí)現(xiàn),那么這個(gè)接口對(duì)象能被 @Autowired注入嗎?這當(dāng)然不行,因?yàn)?@Autowired是根據(jù)類型進(jìn)行裝配的。
那怎么解決這個(gè)問(wèn)題呢?
可以將@Autowired和@Qualifier聯(lián)合使用
@Autowired
// 這里指定bean的名稱,說(shuō)明是根據(jù)名稱進(jìn)行自動(dòng)裝配的
@Qualifier("someServiceBeanForMysql")
private SomeService someService;@Autowired可以標(biāo)注在屬性上、setter方法上、構(gòu)造方法的參數(shù)上。
當(dāng)一個(gè)類中的構(gòu)造方法只有一個(gè),并且構(gòu)造方法的參數(shù)和屬性能對(duì)應(yīng)上,@Autowired 可以省略 (不建議這樣用)
@Resource
@Resource注解也能完成非簡(jiǎn)單類型的注入,那么他和 @Autowired有什么區(qū)別呢?
- @Resource是jdk擴(kuò)展包中的,屬于jdk的一部分,所以該注解是標(biāo)準(zhǔn)注解,更加具有通用性。
- @Autowired是spring框架自己的
- @Resource默認(rèn)根據(jù)名稱自動(dòng)裝配,未指定name時(shí),使用屬性名作為name,如果通過(guò)name找不到的話。會(huì)啟動(dòng)通過(guò)類型自動(dòng)裝配。
- @Autowired時(shí)根據(jù)類型自動(dòng)裝配。如果要根據(jù)名字裝配,需要@Qualifier配合使用
- @Resource用在屬性上、setter方法上
- @Autowired用在屬性上、setter方法上、構(gòu)造方法上、構(gòu)造方法參數(shù)上。
使用@Resource時(shí)先加入相關(guān)依賴
<!-- @Resource注解的依賴-->
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>// 進(jìn)行屬性注入 @Resource(name = "someServiceBean") private SomeService someService;
到此這篇關(guān)于spring6注解式開發(fā)的文章就介紹到這了,更多相關(guān)spring注解式開發(fā)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中的反射,枚舉及l(fā)ambda表達(dá)式的使用詳解
這篇文章主要為大家詳細(xì)介紹了Java的反射,枚舉及l(fā)ambda表達(dá)式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-03-03
Java把數(shù)字格式化為貨幣字符串實(shí)例代碼
這篇文章主要介紹了Java把數(shù)字格式化為貨幣字符串實(shí)例代碼,需要的朋友可以參考下2014-02-02
基于Spring AOP實(shí)現(xiàn)日志自動(dòng)打印功能
這篇文章主要介紹了基于Spring AOP實(shí)現(xiàn)日志自動(dòng)打印功能,文中通過(guò)代碼示例講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2025-01-01
解決mybatisplus插入報(bào)錯(cuò)argument type mismatch的問(wèn)題
這篇文章主要介紹了解決mybatisplus插入報(bào)錯(cuò)argument type mismatch的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11

