以上的代碼咱們發現。咱們都是將@ComponentScan掃描的路徑下的全部類都加載到容器中的。java
而實際需求,咱們並不但願全部的類都建立對象,而是加了組件註解@Controller,@Service,@Repository,@Component的類才建立對象函數
而不加這些標識的類不須要建立對象。測試
所謂本章就是實現經過組件註解限制哪些類是能夠建立對象的,哪些是不能夠的。this
根據得到的類全限制名,得到它的Class對象。經過Class對象判斷類的聲明上是否有組件註解。有就建立對象,沒有就不建立。spa
1.定義四個組件註解code
--Controller-component
package ioc.core.annotation.stereotype; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(value=ElementType.TYPE) @Documented public @interface Controller { /** * 用於設置對象名的屬性 * @return */ String name() default ""; }
--Service--對象
package ioc.core.annotation.stereotype; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 服務層的組件註解定義 * @author ranger * */ @Retention(RetentionPolicy.RUNTIME) @Target(value=ElementType.TYPE) @Documented public @interface Service { /** * 定義用於設置類的對象名的屬性,默認值爲空字符串 * @return */ String name() default ""; }
-Repository-blog
package ioc.core.annotation.stereotype; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(value=ElementType.TYPE) @Documented public @interface Repository { /** * 設置對象名的屬性 * @return */ String name() default ""; }
--Component--接口
package ioc.core.annotation.stereotype; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(value=ElementType.TYPE) @Documented public @interface Component { /** * 設置對象名的屬性 * @return */ String name() default ""; }
2.修改AbstractApplicationContext類,增長了一個isComponent方法判斷是不是組件類
/** * 判斷是不是組件 * @param classType * @return */ private boolean isComponent(Class<?> classType){ //若是是接口,就不能建立對象,直接返回false if(classType.isInterface()){ return false; } Component component = classType.getDeclaredAnnotation(Component.class); Service service = classType.getDeclaredAnnotation(Service.class); Controller controller = classType.getDeclaredAnnotation(Controller.class); Repository repository = classType.getDeclaredAnnotation(Repository.class); //判斷只要有一個組件註解,就返回 if(component!=null||service!=null||controller!=null||repository!=null){ return true; } return false; }
3.修改AbstractApplicationContext類,修改構造函數標紅處的代碼。
1 /** 2 * 將容器操做加載建立對象的代碼寫抽象類裏面,這樣能夠方便之後擴展多種實現。 3 * @param classType 4 */ 5 public AbstractApplicationContext(Class<?> classType) { 6 //判斷配置類是否有Configuration註解 7 Configuration annotation = classType.getDeclaredAnnotation(Configuration.class); 8 if(annotation!=null){ 9 //得到組件掃描註解 10 ComponentScan componentScan = classType.getDeclaredAnnotation(ComponentScan.class); 11 //得到包名 12 this.basePackage = componentScan.basePackages(); 13 //根據包名得到類全限制名 14 //Set<String> classNames = PackageUtils.getClassName(this.basePackage[0], true); 15 //將掃描一個包,修改成多個包 16 Set<String> classNames = PackageUtils.getClassNames(this.basePackage, true); 17 //經過類名建立對象 18 Iterator<String> iteratorClassName = classNames.iterator(); 19 while(iteratorClassName.hasNext()){ 20 21 String className = iteratorClassName.next(); 22 //System.out.println(className); 23 try { 24 //經過類全名建立對象 25 Class<?> objectClassType = Class.forName(className); 26 /* 27 * 判斷若是類權限名對應的不是接口而且包含有 28 * @Component|@Controller|@Service|@Repository 29 * 才能夠建立對象 30 */ 31 if(this.isComponent(objectClassType)){ 32 Object instance = objectClassType.newInstance(); 33 //將對象加到容器中,對象名就類全名 34 this.getContext().addObject(instance.getClass().getSimpleName(),instance); 35 } 36 } catch (InstantiationException e) { 37 e.printStackTrace(); 38 } catch (IllegalAccessException e) { 39 e.printStackTrace(); 40 } catch (ClassNotFoundException e) { 41 e.printStackTrace(); 42 } 43 } 44 } 45 }
1.配置類,掃描ioc.core.test的全部類
1 package ioc.core.test.config; 2 3 import ioc.core.annotation.ComponentScan; 4 import ioc.core.annotation.Configuration; 5 6 //使用定義@Configuration定義該類是一個配置類 7 @Configuration 8 //使用ComponentScan設置掃描包的路徑 9 @ComponentScan(basePackages={"ioc.core.test"}) 10 public class Config { 11 12 }
2.增長不一樣組件註解的普通類
--Controller測試類--
package ioc.core.test.controller; import ioc.core.annotation.stereotype.Controller; @Controller public class UserController { public void login(){ System.out.println("-登陸Controller-"); } }
-UserService--
package ioc.core.test.controller; import ioc.core.annotation.stereotype.Controller; @Controller public class UserController { public void login(){ System.out.println("-登陸Controller-"); } } package ioc.core.test.dao; import ioc.core.annotation.stereotype.Repository; @Repository public class UserDAO { public void save(){ System.out.println("-save保存數據-"); } } package ioc.core.test.service; import ioc.core.annotation.stereotype.Service; /** * 一個普通的類,用於測試是否能夠建立對象 * @author ranger * */ @Service public class UserService { public void login(){ System.out.println("-登陸Service-"); } }
-UserDAO--
package ioc.core.test.dao; import ioc.core.annotation.stereotype.Repository; @Repository public class UserDAO { public void save(){ System.out.println("-save保存數據-"); } }
3.測試類輸出容器內的對象
package ioc.core.test; import org.junit.Test; import ioc.core.impl.AnntationApplicationContext; import ioc.core.test.config.Config; public class AnntationApplicationContextTest { @Test public void login(){ try { AnntationApplicationContext context=new AnntationApplicationContext(Config.class); System.out.println(context.getContext().getObjects()); } catch (Exception e) { e.printStackTrace(); } } }
--測試結果--
加了組件註解的三個類的對象能夠得到,沒有加組件註解的Config類和AnntationApplicationContextTest,說明測試成功。