Spring – Handwriting simulates the underlying principles of Spring

Handwritten Spring

Define configuration class AppConfig

@ComponentScan("com.spring.zsj")
public class AppConfig {

    @Bean
    public ApplicationListener applicationListener() {
        return new ApplicationListener() {
            @Override
            public void onApplicationEvent(ApplicationEvent event) {
                System.out.println("An event was received" + event);
            }
        };
    }

}

Define container ZSJApplicationContext

public class ZSJApplicationContext {

    private Class configClass;

    private Map<String,BeanDefinition> beanDefinitionMap =new HashMap<>();//bean definition

    private Map<String,Object> singleObjects = new HashMap<>(); //Single case pool

    private List<BeanPostProcessor> beanPostProcessorList =new ArrayList<>(); //Post-processing

    public ZSJApplicationContext(Class configClass) {
        this.configClass = configClass;
        scanComponent(configClass);

        //Find the singleton bean
        for (Map.Entry<String,BeanDefinition> entry: beanDefinitionMap.entrySet()
             ) {
            String beanName = entry.getKey();
            BeanDefinition beanDefinition = entry.getValue();
            if(beanDefinition.equals("singleton")){
                Object bean = createBean(beanName, beanDefinition);
                singleObjects.put(beanName,bean);
            }
        }
    }


    private Object createBean(String beanName,BeanDefinition beanDefinition){
        Class clazz = beanDefinition.getType();
        Object newInstance = null;
        try {
            newInstance = clazz.getConstructor().newInstance();

            //Dependency injection
            for (Field field : clazz.getDeclaredFields()) {
                if (clazz.isAnnotationPresent(Autowired.class)) {
                    field.setAccessible(true);
                    field.set(newInstance, getBean(field.getName()));
                }
            }

            //Execute callback method
            if (newInstance instanceof BeanNameAware){
                ((BeanNameAware) newInstance).setBeanName(beanName);
            }


            //Execute the method before initialization
            for (BeanPostProcessor beanPostProcessor: beanPostProcessorList) {
                newInstance = beanPostProcessor.postProcessBeforeInitialization(newInstance, beanName);
            }

            //Whether the current object is instantiated
            if(newInstance instanceof InitializingBean){
                ((InitializingBean) newInstance).afterPropertiesSet();
            }

            //Execute the initialized method (such as Aop)
            for (BeanPostProcessor beanPostProcessor: beanPostProcessorList) {
                newInstance = beanPostProcessor.postProcessAfterInitialization(newInstance, beanName);
            }


        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return newInstance;
    }

    private void scanComponent(Class configClass) {
        if(configClass.isAnnotationPresent(ComponentScan.class)){
            ComponentScan annotation =(ComponentScan) configClass.getAnnotation(ComponentScan.class);
            String path = annotation.value();

             path = path.replace(".", "/");

            ClassLoader classLoader = ZSJApplicationContext.class.getClassLoader();
            URL resource = classLoader.getResource(path);

            File file = new File(resource.getFile());
            if(file.isDirectory()){//If it is a folder, take out the corresponding file
                for (File f: file.listFiles()) {
                    String absolutePath = f.getAbsolutePath();
                    //System.out.println(absolutePath);

                    String com = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
                    String replace = com.replace("", ".");
                   // System.out.println(replace);

                    try {
                        Class<?> clazz = classLoader.loadClass(replace);
                        if(clazz.isAnnotationPresent(Component.class)){

                            //clazz Whether it implements the BeanPostProcessor interface
                            if(BeanPostProcessor.class.isAssignableFrom(clazz)){
                                BeanPostProcessor instance = (BeanPostProcessor)clazz.getConstructor().newInstance();
                                beanPostProcessorList.add(instance);
                            }

                            //Get the name of the bean
                            Component annotation1 = clazz.getAnnotation(Component.class);
                            String beanName = annotation1.value();
                            if("".equals(beanName)){
                                String name = Introspector.decapitalize(clazz.getSimpleName());
                            }


                            BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setType(clazz);

                            if(clazz.isAnnotationPresent(Scope.class)){
                                //round
                                Scope scope = clazz.getAnnotation(Scope.class);
                                String value = scope.value();
                                beanDefinition.setScope(value);
                            }else {
                                //single case
                                beanDefinition.setScope("singleton");
                            }
                            beanDefinitionMap.put(beanName,beanDefinition);
                         // System.out.println(clazz);
                        }
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InstantiationException e) {
                        e.printStackTrace();
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }

                }
            }

         // System.out.println(path);
        }
    }


    //Get the bean object by bean name
    public Object getBean(String beanName){

        if(!beanDefinitionMap.containsKey(beanName)){
                throw new NullPointerException();
        }

        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if(beanDefinition.getScope().equals("singleton")){
            Object singletonBean = singleObjects.get(beanName);
            if(singletonBean== null){
                singletonBean = createBean(beanName, beanDefinition);
                singleObjects.put(beanName,singletonBean);
            }
            return singletonBean;
        }else {
            //prototype
            Object prototypeBean = createBean(beanName, beanDefinition);
            return prototypeBean;
        }
    }
}

Define the annotation @Autowired @Component @Scope @ComponentScan

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







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




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





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

Define the post-processor BeanPostProcessor for initialization

public interface BeanPostProcessor {


    default Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }


    default Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }
}

Define ZSJBeanPostProcessor to implement BeanPostProcesso

@Component
public class ZSJBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {

        if(beanName.equals("userService")){
            Object proxyInstance = Proxy.newProxyInstance(ZSJBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //section
                    System.out.println("Aspect Logic");

                    return method.invoke(bean,args);
                }
            });
            return proxyInstance;
        }


        return bean;
    }
}

Define the initialization interface InitializingBean

public interface InitializingBean {
    void afterPropertiesSet();
}

Define ordinary classes (can be instantiated into singleton beans)

@Component("userService")
@Scope("singleton")
//public class UserService implements InitializingBean {
public class UserService implements UserInterface {

    @Autowired
    private OrderService orderService;



     @ZSanValue("zhangsan")
    private String user;

    //Circular bean represents multiple instances of beans
    public void test(){
        System.out.println(orderService);
    }

// @Override
// public void afterPropertiesSet() {
// System.out.println("Initialization");
// }
}

Define ordinary classes (can be instantiated into prototype beans)

@Component("orderService")
@Scope("prototype")
public class OrderService {

    //Circular bean represents multiple instances of beans
    public void test(){
        System.out.println("hello");
    }
}

Define startup class main

public class Test {
    public static void main(String[] args) {

        //Non-lazy loading singleton bean
// AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// UserService userService = (UserService)context.getBean("userService");
//
// userService.test();


        ZSJApplicationContext context = new ZSJApplicationContext(AppConfig.class);
       UserInterface userService = (UserInterface)context.getBean("userService");
        userService.test();

  // System.out.println(context.getBean("userService"));
// System.out.println(context.getBean("userService"));
// System.out.println(context.getBean("userService"));
// System.out.println(context.getBean("orderService"));
// System.out.println(context.getBean("orderService"));
// System.out.println(context.getBean("orderService"));


// AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(context);
// reader.register(User.class);
// System.out.println(context.getBean("user"));


        StringToUserPropertyEditor propertyEditor = new StringToUserPropertyEditor();
        propertyEditor.setAsText("1");

        User value =new User();
        System.out.println(value);



    }
}

How to use BeanPostProcesso extension

Custom annotation @ZSanValue

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

When using annotations, assign the value of the annotation to the attribute: such as

@ZSanValue("zhangsan")
private String user;

Implement the post-processor, perform pre-initialization operations, and assign custom annotation values to attributes.

@Component
public class ZSanValueBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {

        for (Field field : bean.getClass().getDeclaredFields()) {
            if(field.isAnnotationPresent(ZSanValue.class)){
                field.setAccessible(true);
                try {
                    field.set(bean,field.getAnnotation(ZSanValue.class).value());
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }


        return bean;
    }
}

The callback method uses BeanNameAware

Define callback interface

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

Then the implementation class needs to implement the BeanNameAware interface

@Component("userService")
@Scope("singleton")
//public class UserService implements InitializingBean {
public class UserService implements UserInterface,BeanNameAware {

    @Autowired
    private OrderService orderService;

    @ZSanValue("zhangsan")
    private String user;


    private String beanName;


    //Circular bean represents multiple instances of beans
    public void test(){
        System.out.println(orderService);
    }

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

// @Override
// public void afterPropertiesSet() {
// System.out.println("Initialization");
// }
}

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Java skill treeUse JDBC to operate the databaseDatabase operation 138764 people are learning the system