Small Spring系列五:annotation Injection

Posted java干货

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Small Spring系列五:annotation Injection相关的知识,希望对你有一定的参考价值。


What a sweet burden!A joyful sorrow!

概述

前两章我们已经实现了 setter注入和 constructor注入,本章我们来继续实现 annotation注入。

思路如下:

  1. 读取 xml文件

  2. 对指定 base-package进行扫描,找到对应那些标记为 @Component的类,创建 BeanDefinition

  • 把 base-package下面的 class变成 Resource

  • 使用 ASM读取 Resource中的注解信息

  • 创建 BeanDefinition

  1. 通过 BeanDefinition创建 Bean的实例,根据注解来注入

准备测试类

AccountDao

 
   
   
 
  1. package com.niocoder.dao.v4;


  2. import com.niocoder.stereotype.Component;


  3. @Component

  4. public class AccountDao {

  5. }

ItemDao

 
   
   
 
  1. package com.niocoder.dao.v4;


  2. import com.niocoder.stereotype.Component;


  3. @Component

  4. public class ItemDao {

  5. }

NioCoderService

 
   
   
 
  1. package com.niocoder.service.v4;


  2. import com.niocoder.beans.factory.Autowired;

  3. import com.niocoder.dao.v4.AccountDao;

  4. import com.niocoder.dao.v4.ItemDao;

  5. import com.niocoder.stereotype.Component;


  6. /**

  7. * 测试注解

  8. */

  9. @Component(value = "nioCoder")

  10. public class NioCoderService {


  11. @Autowired

  12. private AccountDao accountDao;


  13. @Autowired

  14. private ItemDao itemDao;


  15. public AccountDao getAccountDao() {

  16. return accountDao;

  17. }


  18. public ItemDao getItemDao() {

  19. return itemDao;

  20. }

  21. }

bean-v4.xml

增加命名空间避免元素冲突,详情参考链接

 
   
   
 
  1. <?xml version="1.0" encoding="UTF-8"?>

  2. <!-- 增加namespace-->

  3. <beans xmlns="http://www.springframework.org/schema/beans"

  4. xmlns:context="http://www.springframework.org/schema/context">


  5. <!-- 扫描哪个包下面的文件 -->

  6. <context:component-scan base-package="com.niocoder.dao.v4,com.niocoder.service.v4">


  7. </context:component-scan>


  8. </beans>

Component和Autowired注解

Component注解主要用于类名上,表明该类为一个注册到容器中的 beanAutowired注解主要用于属性和方法(构造方法, setter方法)上,表明该类初始化时会自动将对应的属性注入。

Component

 
   
   
 
  1. package com.niocoder.stereotype;


  2. import java.lang.annotation.*;


  3. /**

  4. * Component 注解

  5. */

  6. @Target(ElementType.TYPE)

  7. @Retention(RetentionPolicy.RUNTIME)

  8. @Documented

  9. public @interface Component {


  10. String value() default "";

  11. }

Autowired

 
   
   
 
  1. package com.niocoder.beans.factory;


  2. import java.lang.annotation.*;


  3. /**

  4. * Autowired注解

  5. */

  6. @Target({ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.ANNOTATION_TYPE})

  7. @Retention(RetentionPolicy.RUNTIME)

  8. @Documented

  9. public @interface Autowired {


  10. boolean required() default false;

  11. }

PackageResourceLoader

base-package下面的 class变成 Resource

PackageResourceLoader

 
   
   
 
  1. /**

  2. * 将一个目录下的类文件加载为资源文件

  3. *

  4. * @author zhenglongfei

  5. */

  6. @Log

  7. public class PackageResourceLoader {


  8. /**

  9. * 给定一个包的路径,将包下面的文件转换为Resource

  10. *

  11. * @param basePackage

  12. * @return

  13. * @throws IOException

  14. */

  15. public Resource[] getResource(String basePackage) throws IOException {


  16. Assert.notNull(basePackage, "basepackage must not be null");

  17. String location = ClassUtils.convertClassNameToResourcePath(basePackage);

  18. URL url = ClassUtils.getDefaultClassLoader().getResource(location);

  19. File rootDir = new File(url.getFile());


  20. Set<File> matchingFiles = retrieveMatchingFiles(rootDir);

  21. Resource[] resources = new Resource[matchingFiles.size()];

  22. int i = 0;

  23. for (File file : matchingFiles) {

  24. resources[i++] = new FileSystemResource(file);

  25. }

  26. return resources;

  27. }


  28. private Set<File> retrieveMatchingFiles(File rootDir) throws IOException {

  29. if (!rootDir.exists()) {

  30. log.info("Skipping [" + rootDir.getAbsolutePath() + "] because is not exist");

  31. }


  32. if (!rootDir.isDirectory()) {

  33. log.info("Skipping [" + rootDir.getAbsolutePath() + " ] because it a Directory");

  34. }


  35. if (!rootDir.canRead()) {

  36. log.info("Cannot search for matching files underneath directory [" + rootDir.getAbsolutePath() +

  37. "] because the application is not allowed to read the directory");

  38. return Collections.emptySet();

  39. }


  40. Set<File> result = new LinkedHashSet<File>(8);

  41. doRetrieveMatchingFiles(rootDir, result);

  42. return result;

  43. }


  44. protected void doRetrieveMatchingFiles(File dir, Set<File> result) throws IOException {


  45. File[] dirContents = dir.listFiles();

  46. if (dirContents == null) {

  47. log.info("Could not retrieve contents of directory [" + dir.getAbsolutePath() + "]");

  48. return;

  49. }

  50. for (File content : dirContents) {


  51. if (content.isDirectory()) {

  52. if (!content.canRead()) {

  53. log.info("Skipping subdirectory [" + dir.getAbsolutePath() +

  54. "] because the application is not allowed to read the directory");

  55. } else {

  56. doRetrieveMatchingFiles(content, result);

  57. }

  58. } else {

  59. result.add(content);

  60. }


  61. }

  62. }

  63. }

递归的读取一个指定的包目录转换为Resource

PackageResourcesLoaderTest

 
   
   
 
  1. public class PackageResourcesLoaderTest {


  2. @Test

  3. public void testGetResource() throws Exception {

  4. PackageResourceLoader loader = new PackageResourceLoader();

  5. Resource[] resource = loader.getResource("com.niocoder.dao.v4");

  6. Assert.assertEquals(2, resource.length);

  7. }

  8. }

测试PackageResourceLoader

debug调试

代码下载

  • github:https://github.com/longfeizheng/small-spring/tree/20190128annotationv1

代码下载

  • github:https://github.com/longfeizheng/small-spring

参考资料


以上是关于Small Spring系列五:annotation Injection的主要内容,如果未能解决你的问题,请参考以下文章

Spring源码由浅入深系列五 GetBean

Spring系列五:Spring怎么解决循环依赖

[ElasticSearch系列五] Spring Data Elasticsearch 实体类注解说明专攻系

Spring整合JUnit

spring boot 学习笔记

五spring 声明式事务注解配置