注解的存在主要是為了簡化XML的配置。Spring6倡導(dǎo)全注解開發(fā)。
注解開發(fā)的優(yōu)點:提高開發(fā)效率
注解開發(fā)的缺點:在一定程度上違背了OCP原則,使用注解的開發(fā)的前提是需求比較固定,變動較小。
1 注解的注解稱為元注解
自定義一個注解:
package com.sunsplanter.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value = {ElementType.TYPE,ElementType.FIELD})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Component {
String value();
}
- 該注解上面修飾的注解包括:Target注解和Retention注解,這兩個注解被稱為元注解。
- Target注解用來設(shè)置Component注解可以出現(xiàn)的位置,以上代表表示Component注解只能用在類和接口上。
- Retention注解用來設(shè)置Component注解的保持性策略.
SOURCE:注解只被保留在Java源文件中,class文件不包含注解.
CLASS:注解最終被保留到class文件中,但不能被反射機制讀取.
RUNTIME:注解最終被保留到class文件中,并且可以被反射機制讀取.
String value(); 是Component注解中的一個屬性。該屬性類型String,屬性名是value。
2 管中窺豹注解的作用-通過反射機制讀取注解
目標(biāo):只知道報包名:com.sunsplanter.bean,至于這個包下有多少個Bean我們不知道。哪些Bean上有注解,都不知道.
通過程序全自動化判斷: 若Bean類上有Component注解時,則實例化Bean對象,如果沒有,則不實例化對象。
我們準(zhǔn)備兩個Bean,一個上面有注解,一個上面沒有注解。
package com.sunsplanter.bean;
import com.sunsplanter.annotation.Component;
@Component("userBean")
public class User {
}
package com.sunsplanter.bean;
public class Vip {
}
package com.sunsplanter.test;
import com.sunsplanter.annotation.Component;
import java.io.File;
import java.net.URL;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) throws Exception {
// 存放Bean的Map集合。key存儲beanId。value存儲Bean。
Map<String,Object> beanMap = new HashMap<>();
String packageName = "com.sunsplanter.bean";
//將com.sunsplanter.bean轉(zhuǎn)化成com/sunsplanter/bean并存到path中
String path = packageName.replaceAll("\\.", "/");
//獲取這個包在系統(tǒng)中的絕對路徑:file:/D:/study/spring6/spring6-005-Annotation/target/classes/com/sunsplanter/bean
URL url = ClassLoader.getSystemClassLoader().getResource(path);
//獲取一個絕對路徑下的所有子文件,并寫入文件數(shù)組
File file = new File(url.getPath());
File[] files = file.listFiles();
Arrays.stream(files).forEach(f -> {
//獲取兩個類的相對包路徑,如com.sunspalnter.bean.User...
String className = packageName + "." + f.getName().split("\\.")[0];
try {
Class<?> clazz = Class.forName(className);
if (clazz.isAnnotationPresent(Component.class)) {
Component component = clazz.getAnnotation(Component.class);
String beanId = component.value();
Object bean = clazz.newInstance();
beanMap.put(beanId, bean);
}
} catch (Exception e) {
e.printStackTrace();
}
});
System.out.println(beanMap);
}
}
3 聲明Bean的注解
通過注解聲明該類是一個bean類,今后就會被自動創(chuàng)建bean對象.
負(fù)責(zé)聲明Bean的注解,常見的包括四個:
- @Component
- @Controller
- @Service
- @Repository
通過源碼可以看到,@Controller、@Service、@Repository這三個注解都是@Component注解的別名。
也就是說:這四個注解的功能都一樣, 只是為了增強程序的可讀性,建議:
● 控制器類上使用:Controller(主要用于給前端返回數(shù)據(jù)的以及接收前端的數(shù)據(jù)的)
● service類上使用:Service(處理數(shù)據(jù)用的)
● dao類上使用:Repository
他們都是只有一個value屬性。value屬性用來指定bean的id,也就是bean的名字。
4 Spring注解的使用
如果使用以上的注解, 就不必再每一個類都使用一個bean標(biāo)簽管理. 如何使用以上的注解呢?
● 第一步:加入aop的依賴
● 第二步:在配置文件中添加context命名空間
● 第三步:在配置文件中指定掃描的包
● 第四步:在Bean類上使用注解
第一步:加入aop的依賴
當(dāng)加入spring-context依賴之后,會關(guān)聯(lián)加入aop的依賴。所以這一步不用做。
第二步:在配置文件中添加context命名空間, 分別是xmlns:context和xsi:schemeLocation
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
第三步:在配置文件中指定要掃描的包
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.sunsplanter.bean"/>
</beans>
第四步:在Bean類上使用注解
package com.sunsplanter.bean;
import org.springframework.stereotype.Component;
@Component(value = "userBean")
public class User {
}
第四步要小心, 存在兩個兩個Component
第二個時上面學(xué)習(xí)時自己建的,一定要選第一個.
第五步:編寫測試程序
package com.sunsplanter.test;
import com.sunsplanter.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AnnotationTest {
@Test
public void testBean(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println(userBean);
}
}
成功輸出一個對象.
如果注解的屬性名是value,那么value是可以省略的。
例如:
package com.sunsplanter.bean;
import org.springframework.stereotype.Component;
@Component("userBean")
public class User {
}
package com.sunsplanter.test;
import com.sunsplanter.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AnnotationTest {
@Test
public void testBean(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println(userBean);
}
}
仍能輸出一個User對象.
甚至: 如果把value屬性徹底去掉,該類在被創(chuàng)建成bean時會被自動指定一個bean id(名字), 默認(rèn)名字的規(guī)律是:Bean類名首字母小寫即可。
多個包需要掃描的情況
辦法1(常用): 指定需要掃描的多個包的共同父包,掃描這個共同父包. 缺點是如果父包有不需要掃描的包,則會犧牲一些效率.
辦法2: 逗號分隔多個需要掃描的包:
<context:component-scan base-package="com.sunsplanter.bean,com.sunsplanter.dao"/>
5 根據(jù)注解類型選擇性實例化Bean
假設(shè)在某個包下有很多Bean,有的Bean上標(biāo)注了Component,有的標(biāo)注了Controller,有的標(biāo)注了Service,有的標(biāo)注了Repository.
目標(biāo): 現(xiàn)在由于某種特殊業(yè)務(wù)的需要,只允許其中所有的Controller參與Bean管理,其他的都不實例化。
這里為了方便,將這幾個類都定義到同一個java源文件中了:
package com.sunsplanter.spring6.bean3;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
@Component
public class Selective_Instantiation_of_Objects{
public Selective_Instantiation_of_Objects() {
System.out.println("A的無參數(shù)構(gòu)造方法執(zhí)行");
}
}
@Controller
class B {
public B() {
System.out.println("B的無參數(shù)構(gòu)造方法執(zhí)行");
}
}
@Service
class C {
public C() {
System.out.println("C的無參數(shù)構(gòu)造方法執(zhí)行");
}
}
@Repository
class D {
public D() {
System.out.println("D的無參數(shù)構(gòu)造方法執(zhí)行");
}
}
@Controller
class E {
public E() {
System.out.println("E的無參數(shù)構(gòu)造方法執(zhí)行");
}
}
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--
use-default-filters="true" 表示:使用spring默認(rèn)的規(guī)則,只要有Component、Controller、Service、Repository中的任意一個注解標(biāo)注,則進行實例化。
use-default-filters="false" 表示:不再spring默認(rèn)實例化規(guī)則,即使有Component、Controller、Service、Repository這些注解標(biāo)注,也不再實例化。
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 表示只有Controller進行實例化。-->
<context:component-scan base-package="com.sunsplanter.bean" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans>
測試程序:
@Test
public void testChoose(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-choose.xml");
}
輸出注解為@Controller的B,E構(gòu)造方法執(zhí)行.文章來源:http://www.zghlxwxcb.cn/news/detail-810450.html
目標(biāo): 現(xiàn)在由于某種特殊業(yè)務(wù)的需要,除了@Controller外的所有注解都參與Bean管理,僅Controller實例化。文章來源地址http://www.zghlxwxcb.cn/news/detail-810450.html
<!--
use-default-filters="true" 表示:使用spring默認(rèn)的規(guī)則,只要有Component、Controller、Service、Repository中的任意一個注解標(biāo)注,則進行實例化。(不寫默認(rèn)是true)
use-default-filters="false" 表示:不再spring默認(rèn)實例化規(guī)則,即使有Component、Controller、Service、Repository這些注解標(biāo)注,也不再實例化。
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 表示將Controller排除出實例化的范圍。-->
<context:component-scan base-package="com.sunsplanter.bean">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
到了這里,關(guān)于11Spring IoC注解式開發(fā)(上)(元注解/聲明Bean的注解/注解的使用/負(fù)責(zé)實例化Bean的注解)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!