What a sweet burden!A joyful sorrow!
前两章我们已经实现了 setter 注入和 constructor 注入,本章我们来继续实现 annotation 注入。
思路如下:
xml 文件 base-package 进行扫描,找到对应那些标记为 @Component 的类,创建 BeanDefinition
base-package 下面的 class 变成 Resource ASM 读取 Resource 中的注解信息 BeanDefinition BeanDefinition 创建 Bean 的实例,根据注解来注入 package com.niocoder.dao.v4;
import com.niocoder.stereotype.Component;
@Component
public class AccountDao {
}
package com.niocoder.dao.v4;
import com.niocoder.stereotype.Component;
@Component
public class ItemDao {
}
package com.niocoder.service.v4;
import com.niocoder.beans.factory.Autowired;
import com.niocoder.dao.v4.AccountDao;
import com.niocoder.dao.v4.ItemDao;
import com.niocoder.stereotype.Component;
/**
* 测试注解
*/
@Component(value = "nioCoder")
public class NioCoderService {
@Autowired
private AccountDao accountDao;
@Autowired
private ItemDao itemDao;
public AccountDao getAccountDao() {
return accountDao;
}
public ItemDao getItemDao() {
return itemDao;
}
}
增加命名空间避免元素冲突,详情参考 链接
<?xml version="1.0" encoding="UTF-8"?>
<!-- 增加namespace-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context">
<!-- 扫描哪个包下面的文件 -->
<context:component-scan base-package="com.niocoder.dao.v4,com.niocoder.service.v4">
</context:component-scan>
</beans>
Component 注解主要用于类名上,表明该类为一个注册到容器中的 bean 。 Autowired 注解主要用于属性和方法(构造方法, setter 方法)上,表明该类实例化时会自动将对应的属性注入。
package com.niocoder.stereotype;
import java.lang.annotation.*;
/**
* Component 注解
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Component {
String value() default "";
}
package com.niocoder.beans.factory;
import java.lang.annotation.*;
/**
* Autowired注解
*/
@Target({ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default false;
}
把 base-package 下面的 class 变成 Resource
/**
* 将一个目录下的类文件加载为资源文件
*
* @author zhenglongfei
*/
@Log
public class PackageResourceLoader {
/**
* 给定一个包的路径,将包下面的文件转换为Resource
*
* @param basePackage
* @return
* @throws IOException
*/
public Resource[] getResource(String basePackage) throws IOException {
Assert.notNull(basePackage, "basepackage must not be null");
String location = ClassUtils.convertClassNameToResourcePath(basePackage);
URL url = ClassUtils.getDefaultClassLoader().getResource(location);
File rootDir = new File(url.getFile());
Set<File> matchingFiles = retrieveMatchingFiles(rootDir);
Resource[] resources = new Resource[matchingFiles.size()];
int i = 0;
for (File file : matchingFiles) {
resources[i++] = new FileSystemResource(file);
}
return resources;
}
private Set<File> retrieveMatchingFiles(File rootDir) throws IOException {
if (!rootDir.exists()) {
log.info("Skipping [" + rootDir.getAbsolutePath() + "] because is not exist");
}
if (!rootDir.isDirectory()) {
log.info("Skipping [" + rootDir.getAbsolutePath() + " ] because it a Directory");
}
if (!rootDir.canRead()) {
log.info("Cannot search for matching files underneath directory [" + rootDir.getAbsolutePath() +
"] because the application is not allowed to read the directory");
return Collections.emptySet();
}
Set<File> result = new LinkedHashSet<File>(8);
doRetrieveMatchingFiles(rootDir, result);
return result;
}
protected void doRetrieveMatchingFiles(File dir, Set<File> result) throws IOException {
File[] dirContents = dir.listFiles();
if (dirContents == null) {
log.info("Could not retrieve contents of directory [" + dir.getAbsolutePath() + "]");
return;
}
for (File content : dirContents) {
if (content.isDirectory()) {
if (!content.canRead()) {
log.info("Skipping subdirectory [" + dir.getAbsolutePath() +
"] because the application is not allowed to read the directory");
} else {
doRetrieveMatchingFiles(content, result);
}
} else {
result.add(content);
}
}
}
}
递归的读取一个指定的包目录转换为Resource
public class PackageResourcesLoaderTest {
@Test
public void testGetResource() throws Exception {
PackageResourceLoader loader = new PackageResourceLoader();
Resource[] resource = loader.getResource("com.niocoder.dao.v4");
Assert.assertEquals(2, resource.length);
}
}
测试PackageResourceLoader
从零开始造Spring