一起写框架-Ioc内核容器的实现-基础功能-ComponentScan支持组件注解限制(七)

实现功能

以上的代码我们发现。我们都是将@ComponentScan扫描的路径下的所有类都加载到容器中的。

而实际需求,我们并不希望所有的类都创建对象,而是加了组件注解@Controller,@Service,@Repository,@Component的类才创建对象

而不加这些标识的类不需要创建对象。

所谓本章就是实现通过组件注解限制哪些类是可以创建对象的,哪些是不可以的。

实现思路

根据获得的类全限制名,获得它的Class对象。通过Class对象判断类的声明上是否有组件注解。有就创建对象,没有就不创建。

实现步骤

1.定义四个组件注解

--Controller-

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-

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,说明测试成功。

原文地址:https://www.cnblogs.com/zhuyuejiu/p/7819299.html