面试题答案
一键面试关键实现思路
- 定义注解:
- 创建自定义注解,用于标记需要进行依赖注入的字段或方法。例如,定义一个
@Autowired
注解,类似于Spring中的同名注解,用来标识需要自动装配的依赖。
- 创建自定义注解,用于标记需要进行依赖注入的字段或方法。例如,定义一个
- 扫描组件:
- 使用Java的类加载机制和反射,扫描指定包下的所有类。可以通过
ClassLoader
获取类加载器,然后遍历包下的所有.class
文件并加载成Class
对象。 - 识别带有特定注解(如
@Component
,自定义的用于标识组件的注解)的类,这些类将作为依赖注入的候选对象。
- 使用Java的类加载机制和反射,扫描指定包下的所有类。可以通过
- 依赖解析与注入:
- 对于每个被识别为组件的类,利用反射获取其字段和方法。
- 当发现标记了
@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, ElementType.METHOD})
public @interface Autowired {
}
- 扫描组件:
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
public class ComponentScanner {
public static List<Class<?>> scanComponents(String packageName) {
List<Class<?>> components = new ArrayList<>();
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
String path = packageName.replace('.', '/');
Enumeration<URL> resources = classLoader.getResources(path);
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
File directory = new File(resource.getFile());
if (directory.isDirectory()) {
scanDirectory(directory, packageName, components);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return components;
}
private static void scanDirectory(File directory, String packageName, List<Class<?>> components) {
for (File file : directory.listFiles()) {
if (file.isDirectory()) {
scanDirectory(file, packageName + "." + file.getName(), components);
} else if (file.getName().endsWith(".class")) {
String className = packageName + "." + file.getName().substring(0, file.getName().length() - 6);
try {
Class<?> clazz = Class.forName(className);
if (clazz.isAnnotationPresent(Component.class)) {
components.add(clazz);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
- 依赖注入:
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class DependencyInjector {
private Map<Class<?>, Object> componentInstances = new HashMap<>();
public void injectDependencies() {
List<Class<?>> components = ComponentScanner.scanComponents("your.package.name");
for (Class<?> componentClass : components) {
try {
Object componentInstance = componentClass.newInstance();
componentInstances.put(componentClass, componentInstance);
injectFields(componentInstance);
injectMethods(componentInstance);
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
private void injectFields(Object componentInstance) {
Class<?> componentClass = componentInstance.getClass();
for (Field field : componentClass.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
Class<?> fieldType = field.getType();
Object dependency = componentInstances.get(fieldType);
if (dependency != null) {
field.setAccessible(true);
try {
field.set(componentInstance, dependency);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
private void injectMethods(Object componentInstance) {
Class<?> componentClass = componentInstance.getClass();
for (Method method : componentClass.getDeclaredMethods()) {
if (method.isAnnotationPresent(Autowired.class)) {
Class<?>[] parameterTypes = method.getParameterTypes();
Object[] parameters = new Object[parameterTypes.length];
boolean allDependenciesFound = true;
for (int i = 0; i < parameterTypes.length; i++) {
Object dependency = componentInstances.get(parameterTypes[i]);
if (dependency == null) {
allDependenciesFound = false;
break;
}
parameters[i] = dependency;
}
if (allDependenciesFound) {
method.setAccessible(true);
try {
method.invoke(componentInstance, parameters);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
- 使用示例:
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 Component {
}
@Component
public class ServiceA {
// 业务逻辑
}
@Component
public class ServiceB {
@Autowired
private ServiceA serviceA;
// 业务逻辑
}
public class Main {
public static void main(String[] args) {
DependencyInjector injector = new DependencyInjector();
injector.injectDependencies();
}
}
以上代码展示了一个简单的基于Java注解和反射实现依赖注入的框架核心结构,实际应用中还需要考虑更多的细节,如循环依赖处理、作用域管理等。