一塊兒寫框架-Ioc內核容器的實現-基礎功能-ComponentScan支持組件註解限制(七)

實現功能

以上的代碼咱們發現。咱們都是將@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,說明測試成功。

相關文章
相關標籤/搜索