实现功能

以上的代码我们发现。我们都是将@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类,修改构造函数标红处的代码

   /**
* 将容器操作加载创建对象的代码写抽象类里面,这样可以方便以后扩展多种实现。
* @param classType
*/
public AbstractApplicationContext(Class<?> classType) {
//判断配置类是否有Configuration注解
Configuration annotation = classType.getDeclaredAnnotation(Configuration.class);
if(annotation!=null){
//获得组件扫描注解
ComponentScan componentScan = classType.getDeclaredAnnotation(ComponentScan.class);
//获得包名
this.basePackage = componentScan.basePackages();
//根据包名获得类全限制名
//Set<String> classNames = PackageUtils.getClassName(this.basePackage[0], true);
//将扫描一个包,修改为多个包
Set<String> classNames = PackageUtils.getClassNames(this.basePackage, true);
//通过类名创建对象
Iterator<String> iteratorClassName = classNames.iterator();
while(iteratorClassName.hasNext()){ String className = iteratorClassName.next();
//System.out.println(className);
try {
//通过类全名创建对象
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 }
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}

测试代码

1.配置类,扫描ioc.core.test的所有类

 package ioc.core.test.config;

 import ioc.core.annotation.ComponentScan;
import ioc.core.annotation.Configuration; //使用定义@Configuration定义该类是一个配置类
@Configuration
//使用ComponentScan设置扫描包的路径
@ComponentScan(basePackages={"ioc.core.test"})
public class Config { }

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

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

  1. 一起写框架-Ioc内核容器的实现-基础功能-ComponentScan支持多包扫描(六)

    实现功能 1.我们看到@ComponentScan注解一个开始定义就是需要支持,扫描多个包,将多个包的类名获取到.现在就实现这个功能. 实现思路 根据传入的字符串数组,获得多个包下的类全限制名. 实现 ...

  2. 一起写框架-Ioc内核容器的实现-基础功能-ComponentScan(四)

    功能说明 该步骤实现的功能包括: 1. 启动程序时,将@ComponentScan加载的类,创建对象并放在容器里面. 2. 通过ApplicatoinContext的getBean()方法获得容器里面 ...

  3. 一起写框架-Ioc内核容器的实现-基础功能-容器对象名默认首字母小写(八)

    实现功能 --前面实现的代码-- 默认的对象名就类名.不符合Java的命名规范.我们希望默认的对象名首字母小写. 实现思路 创建一个命名规则的帮助类.实现将对大写开头的对象名修改为小写开头. 实现步骤 ...

  4. 一起写框架-Ioc内核容器的实现-基础功能-getBean(五)

    实现的功能 1. 启动程序时,将@ComponentScan加载的类,创建对象并放在容器里面.(查看上一篇文) 2. 通过ApplicatoinContext的getBean()方法获得容器里面的对象 ...

  5. 一起写框架-Ioc内核容器的实现-基础API的定义(三)

    Ioc内核要解决的问题 1.被调用方,在程序启动时就要创建好对象,放在一个容器里面. 2.调用方使用一个接口或类的引用(不用使用new),就可以创建获得对象. 解决这个两个问题的思路 1.定义一个对象 ...

  6. 自己动手写框架——IoC的实现

    先看看 IoC百度百科 优化过程 namespace Test { class Program { static void Main(string[] args) { //场景 某公司客服要回访一些客 ...

  7. 用C写一个web服务器(一) 基础功能

    .container { margin-right: auto; margin-left: auto; padding-left: 15px; padding-right: 15px } .conta ...

  8. spring框架--IOC容器,依赖注入

    思考: 1. 对象创建创建能否写死? 2. 对象创建细节 对象数量 action  多个   [维护成员变量] service 一个   [不需要维护公共变量] dao     一个   [不需要维护 ...

  9. 一起写框架-控制反转(Ioc)概述(二)

    控制反转概述 控制反转(Inversion of Control,英文缩写为IoC),就是将代码的调用的控制权,由调用方转移给被调用方. 如图:修改代码A类的代码,才能将B类的对象换成C类.代码的控制 ...

随机推荐

  1. 怎样学好哲学(lucas+费马小定理)

    怎样学习哲学 时间限制: 1 Sec  内存限制: 128 MB提交: 97  解决: 27[提交][状态][讨论版] 题目描述 OI大师抖儿在夺得银牌之后,顺利保送pku.这一天,抖儿问长者:&qu ...

  2. SQL语句表名或者字段名和保留字冲突解决方法

    最近开发遇到一个很奇葩的问题,简单做一下笔记 select * from Add ... 以上SQL语句会报错. 原因Add是表名,SQL语句保留字中又有Add 解决方法: select * from ...

  3. JS使用默认图片代替页面上无法显示的图片

    1.js方法: function replaceErrorImg(obj) { obj.src="images/common/error.bmp"; } 2.jquery绑定 $( ...

  4. Web API 路由 [一] Convention-Based Routing

    Routing by Naming Convention 在App_Start/ WebApiConfig.cs文件中 routes.MapHttpRoute( name: "API Def ...

  5. Docker到底是什么

    简单讲docker和vm虚拟机类似,都是在同一硬件上虚拟化出多个服务器应用实例的功能,据Bottomley声称,借助经过全面调优的容器系统,你就可以在同一硬件上拥有数量比使用Xen虚拟机或KVM虚拟机 ...

  6. 学习如何看懂SQL Server执行计划(三)——连接查询篇

    三.连接查询部分 --------------------嵌套循环-------------------- /* UserInfo表数据少.Coupon表数据多嵌套循环可以理解为就是两层For循环,外 ...

  7. 【转】Python装饰器与面向切面编程

    原文请参考: http://www.cnblogs.com/huxi/archive/2011/03/01/1967600.html 今天来讨论一下装饰器.装饰器是一个很著名的设计模式,经常被用于有切 ...

  8. c# gdi+输出成不同mime类型的图片

    /// <summary> /// 通过图片的mime类型得到相应的编码器 /// </summary> /// <param name="mimeType&q ...

  9. SQL server学习(五)——T-SQL编程之存储过程

    周五了,祝大家周末愉快. 之前一直在写SQL server的分享,今天再来个T-SQL编程中的存储过程. 存储过程 存储过程(procedure)类似于C语言中的函数,用来执行管理任务或应用复杂的业务 ...

  10. 设置MySQL最大连接数

    <pre name="code" class="sql">在使用MySQL数据库的时候,经常会遇到这么一个问题,就是"Can not co ...