zoukankan      html  css  js  c++  java
  • 一起写框架-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,说明测试成功。

  • 相关阅读:
    js几个常用的弹层
    ubuntu 更新源 或者 apt-get install 出错404 not found ,Failed to fetch
    vmware ubuntu 解决 宿主机与虚拟机互相ping不通,虚拟机无线上网的解决办法
    mediawiki资料
    mediawiki问题
    JavaEE异常
    前端网站收藏
    依赖注入--setting注入和构造器注入
    Spring注入Bean
    Spring简介
  • 原文地址:https://www.cnblogs.com/zhuyuejiu/p/7819299.html
Copyright © 2011-2022 走看看