实现功能
以上的代码我们发现。我们都是将@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,说明测试成功。
时间: 2024-10-31 09:53:12