自定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
String value() default "";
}
定义配置类包含要扫描的包
@ComponentScan(value = "com.sparrow.spring.component")
public class SparrowSpringConfig {
}
在component包下定义四个bean类
@Component("sparrow")
public class MyComponent {
}
public class UserController {
@Resource(name = "userService")
private UserService userService;
public void sayOk() {
userService.sayOk();
}
}
@Repository
public class UserDao {
}
@Service
public class UserService {
public void sayOk() {
System.out.println("UserServiceOk。。。");
}
}
自定义容器
package com.sparrow.spring.annotation;
import com.sparrow.spring.application.SpaApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.io.File;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Author: 诉衷情の麻雀
* @Description: TODO
* @DateTime: 2023/7/24 16:22
**/
public class SparrowSpringApplicationContext {
private Class configClass;
private final ConcurrentHashMap<String, Object> ioc = new ConcurrentHashMap<>();
public SparrowSpringApplicationContext(Class configClass) {
this.configClass = configClass;
//1.获取要扫描的包
ComponentScan componentScan = (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
//2.通过componentScan的value 即要扫描的包
String path = componentScan.value();
System.out.println("要扫描的包=" + path);
//3.得到要扫描包下的所有资源(.class) 得到类的加载器
ClassLoader classLoader = SpaApplicationContext.class.getClassLoader();
//4. 通过类的加载器获取到要扫描的包的资源
path = path.replace(".", "/");
URL resource = classLoader.getResource(path);
System.out.println("resource" + resource);
//5.将要加载的资源(.class)路径下的文件进行遍历
File file = new File(resource.getFile());
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
String absolutePath = f.getAbsolutePath();
//过滤 只处理.class文件
if (absolutePath.endsWith(".class")) {
//1.获取到类名
String className = absolutePath.substring(absolutePath.lastIndexOf("\\") + 1, absolutePath.indexOf(".class"));
//2.获取类的完整路径
String classFullName = path.replace("/", ".") + "." + className;
System.out.println("classFullName=" + classFullName);
//判断该类有没有注解
//Class.forName 可以反射加载类对象,可以调用类的静态方法
//classLoader.loadClass该类不会调用 只是加载了类的信息
try {
Class<?> aClass = classLoader.loadClass(classFullName);
if (aClass.isAnnotationPresent(Component.class) || aClass.isAnnotationPresent(Controller.class) || aClass.isAnnotationPresent(Service.class) || aClass.isAnnotationPresent(Repository.class)) {
if (aClass.isAnnotationPresent(Component.class)) {
Component component = aClass.getDeclaredAnnotation(Component.class);
String id= component.value();
if (!"".endsWith(id)) {
className = id;
}
}
//这时候就可以反射对象,并放入到容器中
Class<?> clazz = Class.forName(classFullName);
Object newInstance = clazz.newInstance();
//放入到容器中
ioc.put(StringUtils.uncapitalize(className), newInstance);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
}
public Object getBean(String name) {
return ioc.get(name);
}
public ConcurrentHashMap<String, Object> getIoc() {
return ioc;
}
}
测试程序
public class Test {
public static void main(String[] args) {
SparrowSpringApplicationContext springApplicationContext = new SparrowSpringApplicationContext(SparrowSpringConfig.class);
Object userController = springApplicationContext.getBean("userController");
System.out.println(userController);
ConcurrentHashMap<String, Object> ioc = springApplicationContext.getIoc();
System.out.println("ioc = " + ioc);
}
}
从以下截图我们可以看到成功获取到了容器并且注解bean在容器里面,也可以通过bean的name获取