2、手写模拟Spring底层原理

该文通过代码示例展示了如何模拟Spring框架中的注解加载机制,包括@ComponentScan、@Component、@Autowired等,以及Bean的单例模式、Scope、Lazy加载。同时,文中提到了对BeanNameAware和ApplicationContextAware接口的实现,以及@Transactional注解的模拟处理,以增强Bean的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
项目的初始化结构如上图,模拟spring中的注解和加载方式,首先是ComponentScan ,Component,

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
    String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
    String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {
    String value() default "";
}
@ComponentScan("com.guojia.service")
public class AppConfig {
}
@Component
public class OrderService {
}
@Component("userService")
public class UserService {
@Autowired
private OrderService orderService;
    public void test(){
        System.out.println("userServiceTest");
    }
}
public class Test {
    public static void main(String[] args) {
        GuojiaApplicationContext applicationContext = new GuojiaApplicationContext(AppConfig.class);
        UserService userService = (UserService)  applicationContext.getBean("userService");
        userService.test();
    }
}
// 由于Test类的main方法中类需要加载参数

public class GuojiaApplicationContext {
    private Class configClass;
    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
    private Map<String,Object> singletonObjects = new HashMap<>();
    public GuojiaApplicationContext(Class<?> configClass) {
        this.configClass = configClass;
        scan(configClass);
    }

    private void scan(Class<?> configClass) {
        // 如果存在这个注解
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan componentScan = configClass.getAnnotation(ComponentScan.class);
            // 注解所在的target文件夹的位置
            String path = componentScan.value();
            path = path.replace(".", "/");
            System.out.println("ComponentScan路径:" + path);
            ClassLoader classLoader = this.getClass().getClassLoader();
            URL resource = classLoader.getResource(path);
            File file = new File(resource.getFile());
            if (file.isDirectory()) {
                for (File f : Objects.requireNonNull(file.listFiles())) {
                    String absolutePath = f.getAbsolutePath();
                    absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
                    absolutePath = absolutePath.replace("\\", ".");
                    try {
                        Class<?> clazz = classLoader.loadClass(absolutePath);
                        if(clazz.isAnnotationPresent(Component.class)){
                            Component component = clazz.getAnnotation(Component.class);
                            String beanName = component.value();
                            // 默认类名小写开头
                            if("".equals(beanName)){
                                beanName = Introspector.decapitalize(clazz.getSimpleName());
                                System.out.println(beanName);
                            }
                            BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setType(clazz);
                            beanDefinitionMap.put(beanName,beanDefinition);
                        }
                    } catch (ClassNotFoundException e) {
                        throw new RuntimeException(e);
                    }

                }
            }

        }
    }
    //模拟getBean方法

    public Object getBean(String beanName) {
        if(!beanDefinitionMap.containsKey(beanName)){
          throw new NullPointerException(beanName+"未加载");
        }
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if("singleton".equals(beanDefinition.getScope())){
            Object singleton = singletonObjects.get(beanName);
            if(singleton==null){
                singletonObjects.put(beanName,createBean(beanName,beanDefinition));
            }
            return singleton;
        }else {
          Object bean =  createBean(beanName,beanDefinition);
          return bean;
        }
    }

    private Object createBean(String beanName, BeanDefinition beanDefinition) {
        Class clazz = beanDefinition.getType();
        try {
            Object instance = clazz.getConstructor().newInstance();
            for(Field field : clazz.getDeclaredFields()){
                if(field.isAnnotationPresent(Autowired.class)){
                    field.setAccessible(true);
                    field.set(instance,getBean(field.getName()));
                }
            }
            return instance;
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }
}

执行main方法后
在这里插入图片描述
另外,我们也可以在UserService上加@Scope注解,来实现单例或者其他类型

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Scope {
    String value() default "";
}

@Component("userService")
@Scope("singleton")
public class UserService {
    public void test(){
        System.out.println("userServiceTest");
    }
}

在GuojiaApplicationContext的scan方法中添加

   if (clazz.isAnnotationPresent(Component.class)) {
                        BeanDefinition beanDefinition = new BeanDefinition();
                        beanDefinition.setType(clazz);
                        beanDefinition.setLazy(clazz.isAnnotationPresent(Lazy.class));
                        if (clazz.isAnnotationPresent(Scope.class)) {
                            beanDefinition.setScope(clazz.getAnnotation(Scope.class).value());
                        } else {
                            beanDefinition.setScope("singleton");
                        }

                        String beanName = clazz.getAnnotation(Component.class).value();
                        if (beanName.isEmpty()) {
                            beanName = Introspector.decapitalize(clazz.getSimpleName());
                        }

                        beanDefinitionMap.put(beanName, beanDefinition);

                    }

同理,如果在Userservice上添加@Lazy注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Lazy {

    boolean value() default true;

}
@Component("userService")
@Scope("singleton")
@Lazy
public class UserService {
    public void test(){
        System.out.println("userServiceTest");
    }
}

需要在GuojiaApplicationContext的scan方法中添加

  if(clazz.isAnnotationPresent(Lazy.class)){
                                beanDefinition.setLazy(clazz.getAnnotation(Lazy.class).value());
                            }

我们的注解类型添加到beanMap里面后,需要创建bean,如果使用bean,直接根据beanName获取到对应的对象
所以我们需要遍历beanDefinitonMap,如果是单例的存储到singletonObjects 的map里面,getBean使用的时候直接去singletonObjects里面取

  public GuojiaApplicationContext(Class<?> configClass) {
        this.configClass = configClass;
        scan(configClass);
        for (String beanName : beanDefinitionMap.keySet()) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            if (beanDefinition.getScope().equals("singleton") && !beanDefinition.isLazy()) {
                Object bean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName, bean);
            }
        }
    }
    public Object getBean(String beanName) {
        if(!beanDefinitionMap.containsKey(beanName)){
          throw new NullPointerException(beanName+"未加载");
        }
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if("singleton".equals(beanDefinition.getScope())){
            Object singleton = singletonObjects.get(beanName);
            if(singleton==null){
                singletonObjects.put(beanName,createBean(beanName,beanDefinition));
            }
            return singleton;
        }else {
          Object bean =  createBean(beanName,beanDefinition);
          return bean;
        }
    }

spring的bean生命周期有BeanNameAware ,如果我们的OrderService实现了BeanNameAware接口

public interface BeanNameAware {
    void setBeanName(String name);
}

@Component
public class OrderService implements BeanNameAware {
    @Override
    public void setBeanName(String name) {

    }
}

我们需要在GuojiaApplicationContext的createBean方法里面添加对应的处理

 Class clazz = beanDefinition.getType();
        try {
            Object instance = clazz.getConstructor().newInstance();
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(Autowired.class)) {
                    field.setAccessible(true);
                    field.set(instance, getBean(field.getName()));
                }
            }
            if(instance instanceof BeanNameAware){
                ((BeanNameAware) instance).setBeanName(beanName);
            }

如果orderService还实现了ApplicationContextAware接口,则

public interface ApplicationContextAware {
    void setApplicationContext(ZhouyuApplicationContext applicationContext);
}
@Component
public class OrderService implements BeanNameAware, ApplicationContextAware {
    private GuojiaApplicationContext applicationContext;
    private String beanName;

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }

    @Override
    public void setApplicationContext(GuojiaApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
}

在BeanNameAware下面接着写对应的代码

    if (instance instanceof ApplicationContextAware) {
                ((ApplicationContextAware) instance).setApplicationContext(this);
            }

如果我们OrderService上添加了@Transactional 注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Transactional {
}
需要在上方的if方法下接着写
  if (clazz.isAnnotationPresent(Transactional.class)) {
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(clazz);
                Object target = o;
                enhancer.setCallback(new MethodInterceptor() {
                    @Override
                    public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                        System.out.println("开启事务");
                        Object result = method.invoke(target, objects);
                        System.out.println("提交事务");
                        return result;
                    }
                });
                o = enhancer.create();
            }

以上是一些spring的注解模拟,下一篇文章是实际的spring中对应的类和方法讲解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值