通过代码模拟实现@Autowired,@Component,@Resource,@Component注解的简单的自我实现。
具体实现过程,请看代码注释以及代码。
测试类如下:
import com.itheima.AutowiredBeanPostProcessor;
import com.itheima.BeanFactory;
import com.itheima.BeanFactoryImpl;
import com.itheima.ResourceBeanPostProcessor;
import com.test.sub.C;
public class Test1 {
public static void main(String[] args) {
//创建一个我们自己编写的BeanFactory工厂类。
// 直接通过工厂类即可获取标有,@Autowired,@Component,@Resource注解的对象
BeanFactory beanFactory = new BeanFactoryImpl(MyConfig.class,
new ResourceBeanPostProcessor(), new AutowiredBeanPostProcessor());
A a = beanFactory.getBean(A.class);
B b = beanFactory.getBean(B.class);
C c = beanFactory.getBean(C.class);
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println("---------------");
System.out.println(a.getB());
}
}
BeanFactory抽象类:
public interface BeanFactory {
/**
* 将某个类型注册到 spring 容器
* @param clz 类型
*/
void register(Class<?> clz);
/**
* 获取 bean 实例
* @param clz 类型
* @return 对象实例
* @param <T> 泛型
*/
<T> T getBean(Class<T> clz);
void replace(Class<?> clz, Object proxy);
}
?对应的实现类:
import java.util.*;
public class BeanFactoryImpl implements BeanFactory {
private Map<Class<?>, Object> map = new HashMap<>(); // singletonObjects
private List<BeanPostProcessor> list = new ArrayList<>();
/**
*
* @param config 配置文件的class
* @param processors bean的后置增强器类
*/
public BeanFactoryImpl(Class<?> config, BeanPostProcessor... processors) {
list.addAll(Arrays.asList(processors));
//如果配置 文件带有@ComponentScan注解
if (config.isAnnotationPresent(ComponentScan.class)) {
//获取配置文件上的注解
ComponentScan cs = config.getAnnotation(ComponentScan.class);
//获取注解中的value值
String packageName = cs.value();
try {
//将带有@Component的注解的所有的类对象,加载到容器中
ComponentScanner.scan(this, packageName);
} catch (Exception e) {
throw new RuntimeException(e);
}
// 原始对象 a, b
/*map.forEach((clz,bean)->{
// a -> a 代理 -> a @Autowired -> a @Resource
for (BeanPostProcessor beanPostProcessor : list) {
beanPostProcessor.enhance(this, bean);
}
});*/
for (BeanPostProcessor beanPostProcessor : list) {
for (Object bean : map.values()) {
//执行增强类的增强方法
beanPostProcessor.enhance(this, bean);
}
}
}
}
@Override
public void register(Class<?> clz) {
try {
Object obj = clz.getDeclaredConstructor().newInstance();
map.put(clz, obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public <T> T getBean(Class<T> clz) {
Object obj = map.get(clz);
return clz.cast(obj);
}
@Override
public void replace(Class<?> clz, Object proxy) {
map.put(clz, proxy);
}
}
后置处理器接口类:
public interface BeanPostProcessor {
/**
* 增强 bean 的功能
* @param beanFactory 容器
* @param bean 待增强的 bean
*/
void enhance(BeanFactory beanFactory, Object bean);
}
?
?
Autowired注解声明类:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//该注解用于指定被修饰的注解在运行时保留。这意味着注解信息将在运行时通过反射机制可以被读取和使用。
@Retention(RetentionPolicy.RUNTIME)
//表示当前的这个注解,可以标注在类字段上
@Target(ElementType.FIELD)
public @interface Autowired {
}
Autoeired的后置处理器类:
import com.itheima.aop.HeimaProxy;
import java.lang.reflect.Field;
public class AutowiredBeanPostProcessor implements BeanPostProcessor{
@Override
public void enhance(BeanFactory beanFactory, Object a) {
if (a instanceof HeimaProxy proxy) {
a = proxy.target();
}
// a.getClass() 得到的是代理类型
// a.getClass().getSuperclass() 得到原始类型
//获取当前对象a的所有属性并进行遍历
for (Field field : a.getClass().getDeclaredFields()) {
//如果属性a上包含注解类,Autowired.class
if (field.isAnnotationPresent(Autowired.class)) {
//获取标有@Autowird注解的属性的类型
Class<?> type = field.getType();
//从bean工厂类中,根据类型获取到该属性的对象
Object b = beanFactory.getBean(type);
//设置当前属性为可访问状态(private修饰的属性,同样可以访问了)
field.setAccessible(true);
try {
// 给代理对象继承过来的属性b进行了依赖注入
field.set(a, b);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
}
Resource注解声明类:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Resource {
}
Resource后置处理器类:
import java.lang.reflect.Field;
public class ResourceBeanPostProcessor implements BeanPostProcessor{
@Override
public void enhance(BeanFactory beanFactory, Object a) {
for (Field field : a.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(Resource.class)) {
Class<?> type = field.getType();
Object b = beanFactory.getBean(type);
field.setAccessible(true);
try {
field.set(a, b);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
}
ComponentScan注解声明类:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
String value();
}
componnet注解声明类:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
}
ComponentScanner类:
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 职责:找到某个 package 下所有加了 @Component 注解的类,把它们加入容器管理
*/
public class ComponentScanner {
/**
* 扫描加了 @Component 注解的类,注册到 BeanFactory
* @param beanFactory 容器
* @param packageName 包名
* @throws Exception
*/
public static void scan(BeanFactory beanFactory, String packageName) throws Exception {
//获取指定包名下的所有的文件
List<File> files = getClassFiles(packageName);
String p = packageName.replace(".", "\\");
for (File f : files) {
// System.out.println(f);
//截取正确的全路径包名
// D:\黄埔班\mini-spring\target\classes\com\test\A.class => com.test.A
String t = f.getAbsolutePath();
t = t.substring(0, t.lastIndexOf(".class"));
t = t.substring(t.lastIndexOf(p));
t = t.replace("\\", ".");
// System.out.println(t);
//根据全路径包名,通过反射创建class
Class<?> clz = Class.forName(t);
//如果此类上有@Component注解,则将当前类对象注册到beanFactory中。
if (clz.isAnnotationPresent(Component.class)) {
beanFactory.register(clz);
}
}
}
/**
* 根据包名,得到所有类文件
* @param packageName 包名
* @return 文件集合
*/
private static List<File> getClassFiles(String packageName) throws URISyntaxException {
//将包中的点,换成路径中的/
packageName = packageName.replace(".", "/");
//获取当前项目的类路径(java项目的类路径一般有两种:1.项目 编译后的target/classes 2.项目源码中的resource目录)
URL resource = Thread.currentThread().getContextClassLoader().getResource(packageName);
Path start =Path.of(resource.toURI());
//遍历指定的文件夹下的所有文件
try (Stream<Path> walk = Files.walk(start)) {
List<File> list = walk.filter(p -> p.toString().endsWith(".class"))
.map(p -> p.toFile())
.collect(Collectors.toList());
return list;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
类A:
import com.itheima.Autowired;
import com.itheima.Component;
import com.itheima.Resource;
@Component
public class A {
@Autowired
// @Resource
B b;
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
public void foo() {
System.out.println("foo");
}
}
类B:
import com.itheima.Component;
@Component
public class B {
public void bar() {
System.out.println("bar");
}
}
类c:
import com.itheima.Component;
@Component
public class C {
}
?持续更新中................,关注不迷路。
?
?
?
?
?
?