手写Spring3.x以上

一.准备工作

1.创建maven项目

2.创建配置类,加载容器类,启动类

 

 

public class CharkeyApplicationContext {

    private Class appConfig;

    public CharkeyApplicationContext(Class appConfig) {
        this.appConfig = appConfig;
    }

    public Object getBean(String name) {
       return null;
    }
}
public class Application {

    public static void main(String[] args) {
        CharkeyApplicationContext chakeyApplicationContext = new CharkeyApplicationContext(AppConfig.class);
        Object bean1 = chakeyApplicationContext.getBean("userService");
        System.out.println(bean1);
    }
}

 二.IOC之扫描加载Bean对象

1.添加扫描Config类注解compentScan

2.添加compent注解标注扫描类

3.Bean加载到容器中

4.调用getBean

 

package annotiton;

import java.lang.annotation.*;

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

    String value() default "";
}
package annotiton;

import java.lang.annotation.*;

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

    String value();
}
package annotiton;

public class BeanDefinition {

    private Class clazz;

    private String scope;//单例 多例

    public BeanDefinition() {
    }

    public BeanDefinition(Class clazz, String scope) {
        this.clazz = clazz;
        this.scope = scope;
    }

    public Class getClazz() {
        return clazz;
    }

    public void setClazz(Class clazz) {
        this.clazz = clazz;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }
}
@Component("orderService")
public class OrderServiceImpl implements OrderService {
}
@Component("userService")
public class UserServiceImpl implements UserService {


}
package config;

import annotiton.ComponentScan;

@ComponentScan("service.impl")
public class AppConfig {
}
package spring;

import annotiton.BeanDefinition;
import annotiton.Component;
import annotiton.ComponentScan;

import java.io.File;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;

public class CharkeyApplicationContext {

    private Class appConfig;

    private static ConcurrentHashMap<String, BeanDefinition> beanDifinitionMap = new ConcurrentHashMap<>();

    public CharkeyApplicationContext(Class configClass) {
        this.appConfig = appConfig;

        //扫描bean
        scan(configClass);
    }

    public Object getBean(String name) {
        BeanDefinition beanDefinition = beanDifinitionMap.get(name);
        return beanDefinition;
    }

    public void scan(Class app) {

        boolean annotationPresent = app.isAnnotationPresent(ComponentScan.class);
        if (!annotationPresent) throw new RuntimeException("没有配置类");

        ComponentScan componentScan = (ComponentScan) app.getDeclaredAnnotation(ComponentScan.class);
        String path = componentScan.value();
        System.out.println(path);

        ClassLoader classLoader = CharkeyApplicationContext.class.getClassLoader();
        path = path.replace(".", "/");
        System.out.println(path);
        URL resource = classLoader.getResource("service/impl");//"com/charkey/service"
        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (int i = 0; i < files.length; i++) {
                File file1 = files[i];
                String absolutePath = file1.getAbsolutePath();
                System.out.println(absolutePath);
                absolutePath = absolutePath.substring(absolutePath.indexOf("service"), absolutePath.indexOf(".class"));
                System.out.println(absolutePath);
                absolutePath = absolutePath.replace("\\", ".");
                System.out.println(absolutePath);

                Class<?> clazz = null;
                try {
                    clazz = classLoader.loadClass(absolutePath);

                    boolean isComponent = clazz.isAnnotationPresent(Component.class);
                    if (!isComponent) continue;
                    Component declaredAnnotation = clazz.getDeclaredAnnotation(Component.class);

                    String beanName = declaredAnnotation.value();

                    BeanDefinition beanDefinition = new BeanDefinition();
                    beanDefinition.setClazz(clazz);
                    beanDifinitionMap.put(beanName, beanDefinition);


                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }

                if (clazz != null && clazz.isAnnotationPresent(Component.class)) {
                    System.out.println(absolutePath);
                }
            }
        }

    }
}

 

三.Scope注解实现可配置的单例,多例对象

1.添加Scope注解,默认为singleton

2.被Compoent注解扫描的类被scope注解定义为Prototype视为多例,否则为单例

3.Bean加载到容器中

4.单例时从bean容器中取出,多例时创建新对象

package annotiton;

import java.lang.annotation.*;

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

    String value() default "singleton";
}

 

 

 

 

 

 

package spring;

import annotiton.BeanDefinition;
import annotiton.Component;
import annotiton.ComponentScan;
import annotiton.Scope;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;

public class CharkeyApplicationContext {

    private Class appConfig;

    private static ConcurrentHashMap<String, BeanDefinition> beanDifinitionMap = new ConcurrentHashMap<>();

    public CharkeyApplicationContext(Class configClass) {
        this.appConfig = appConfig;

        //扫描bean
        scan(configClass);
    }

    public Object getBean(String name) {
        BeanDefinition beanDefinition = beanDifinitionMap.get(name);
        String scope = beanDefinition.getScope();
        if(scope.equals("prototype"))return createBean(name, beanDefinition);
        return beanDefinition;
    }

    public Object createBean(String beanName, BeanDefinition beanDefinition) {
        Object object = null;
        try {
            Class clazz = beanDefinition.getClazz();
            object = clazz.getDeclaredConstructor().newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return object;
    }

    public void scan(Class app) {

        boolean annotationPresent = app.isAnnotationPresent(ComponentScan.class);
        if (!annotationPresent) throw new RuntimeException("没有配置类");

        ComponentScan componentScan = (ComponentScan) app.getDeclaredAnnotation(ComponentScan.class);
        String path = componentScan.value();
        System.out.println(path);

        ClassLoader classLoader = CharkeyApplicationContext.class.getClassLoader();
        path = path.replace(".", "/");
        System.out.println(path);
        URL resource = classLoader.getResource("service/impl");//"com/charkey/service"
        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (int i = 0; i < files.length; i++) {
                File file1 = files[i];
                String absolutePath = file1.getAbsolutePath();
                System.out.println(absolutePath);
                absolutePath = absolutePath.substring(absolutePath.indexOf("service"), absolutePath.indexOf(".class"));
                System.out.println(absolutePath);
                absolutePath = absolutePath.replace("\\", ".");
                System.out.println(absolutePath);

                Class<?> clazz = null;
                try {
                    clazz = classLoader.loadClass(absolutePath);

                    boolean isComponent = clazz.isAnnotationPresent(Component.class);
                    if (!isComponent) continue;
                    Component declaredAnnotation = clazz.getDeclaredAnnotation(Component.class);
                    String beanName = declaredAnnotation.value();

                    String scopeVal = "singleton";//默认单例Bean
                    boolean isScope = clazz.isAnnotationPresent(Scope.class);
                    if(isScope){
                        Scope scope1 = clazz.getDeclaredAnnotation(Scope.class);
                        scopeVal = scope1.value();
                    }

                    BeanDefinition beanDefinition = new BeanDefinition();
                    beanDefinition.setClazz(clazz);
                    beanDefinition.setScope(scopeVal);
                    beanDifinitionMap.put(beanName, beanDefinition);

                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }

                if (clazz != null && clazz.isAnnotationPresent(Component.class)) {
                    System.out.println(absolutePath);
                }
            }
        }

    }
}

 

四.使用Autowired控制反转以及依赖注入

1.添加Autowired注解,增加requied属性

2.模拟DI创建bean容器

3.在创建bean时,把bean中的被autowired定义的属性加载

package annotiton;

import java.lang.annotation.*;

@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

    boolean value() default true;
}

 

 

 

 

package spring;

import annotiton.*;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;

public class CharkeyApplicationContext {

    private Class appConfig;

    private static ConcurrentHashMap<String, BeanDefinition> beanDifinitionMap = new ConcurrentHashMap<>();

    private static ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();

    public CharkeyApplicationContext(Class configClass) {
        this.appConfig = appConfig;

        //扫描bean
        scan(configClass);

        beanDifinitionMap.forEach((beanName, clazz) -> {
            String scope = clazz.getScope();
            if (scope.equals("singleton")) {
                Object bean = createBean(beanName, clazz);
                singletonObjects.put(beanName, bean);
            }
        });
    }

    public Object getBean(String name) {
        BeanDefinition beanDefinition = beanDifinitionMap.get(name);
        String scope = beanDefinition.getScope();
        if(scope.equals("prototype"))return createBean(name, beanDefinition);
        return singletonObjects.get(name);
    }

    public Object createBean(String beanName, BeanDefinition beanDefinition) {
        Class clazz = beanDefinition.getClazz();

        try {
            Object o = clazz.getDeclaredConstructor().newInstance();

            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field field : declaredFields) {
                boolean annotationPresent = field.isAnnotationPresent(Autowired.class);
                if (annotationPresent) {
                    Autowired autowired = (Autowired) clazz.getDeclaredAnnotation(Autowired.class);
                    boolean requied = autowired.value();
                    if(requied && o == null)throw new RuntimeException("没有找到bean");
                    Object bean = getBean(field.getName());
                    field.setAccessible(true);
                    field.set(o, bean);
                }
            }
            return o;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public void scan(Class app) {

        boolean annotationPresent = app.isAnnotationPresent(ComponentScan.class);
        if (!annotationPresent) throw new RuntimeException("没有配置类");

        ComponentScan componentScan = (ComponentScan) app.getDeclaredAnnotation(ComponentScan.class);
        String path = componentScan.value();
        System.out.println(path);

        ClassLoader classLoader = CharkeyApplicationContext.class.getClassLoader();
        path = path.replace(".", "/");
        System.out.println(path);
        URL resource = classLoader.getResource("service/impl");//"com/charkey/service"
        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (int i = 0; i < files.length; i++) {
                File file1 = files[i];
                String absolutePath = file1.getAbsolutePath();
                System.out.println(absolutePath);
                absolutePath = absolutePath.substring(absolutePath.indexOf("service"), absolutePath.indexOf(".class"));
                System.out.println(absolutePath);
                absolutePath = absolutePath.replace("\\", ".");
                System.out.println(absolutePath);

                Class<?> clazz = null;
                try {
                    clazz = classLoader.loadClass(absolutePath);

                    boolean isComponent = clazz.isAnnotationPresent(Component.class);
                    if (!isComponent) continue;
                    Component declaredAnnotation = clazz.getDeclaredAnnotation(Component.class);
                    String beanName = declaredAnnotation.value();

                    String scopeVal = "singleton";//默认单例Bean
                    boolean isScope = clazz.isAnnotationPresent(Scope.class);
                    if(isScope){
                        Scope scope1 = clazz.getDeclaredAnnotation(Scope.class);
                        scopeVal = scope1.value();
                    }

                    BeanDefinition beanDefinition = new BeanDefinition();
                    beanDefinition.setClazz(clazz);
                    beanDefinition.setScope(scopeVal);
                    beanDifinitionMap.put(beanName, beanDefinition);

                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }

                if (clazz != null && clazz.isAnnotationPresent(Component.class)) {
                    System.out.println(absolutePath);
                }
            }
        }

    }
}

 五. Bean的生命周期

1.创建InitializingBean接口,定义初始化方法

2.修饰到需要初始化的Compent类上

3.创建Bean时,触发初始化方法

package annotiton;

public interface InitializingBean {

    void afterPropertiesSet() throws Exception;
}

 

 

package service.impl;

import annotiton.Autowired;
import annotiton.Component;
import annotiton.InitializingBean;
import annotiton.Scope;
import service.OrderService;
import service.UserService;

@Component("userService")
@Scope("prototype")
public class UserServiceImpl implements UserService, InitializingBean {

    @Autowired
    private OrderService orderService;

    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void testAutowired(){
        System.out.println(orderService);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("bean初始化。。。");
        //System.out.println(getName());
    }
}

 六. 监听Bean的初始化前、初始化、初始化后

1.Bean生命周期接口及实现 BeanPostProcessor 和 MyBeanPostInitialization,并在MyBeanPostInitialization添加Compent

2.扫描时将BeanPostProcessor 放到容器中

3.创建Bean时,从容器中取出BeanPostProcessor ,并执行初始化方法

package annotiton;

public interface BeanPostProcessor {

    Object postProcessorBeforeInintion(String beanName, Object bean);

    Object postProcessorAfterInintion(String beanName, Object bean);
}
package service.impl;

import annotiton.BeanPostProcessor;
import annotiton.Component;
import service.OrderService;

@Component
public class MyBeanPostInitialization implements BeanPostProcessor {
    @Override
    public Object postProcessorBeforeInintion(String beanName, Object bean) {
        if (beanName.equals("orderService")) {
            OrderService orderService = (OrderService) bean;
            System.out.println("Bean开始初始化。。。");
            orderService.setName("charkey");
        }
        return bean;
    }

    @Override
    public Object postProcessorAfterInintion(String beanName, Object bean) {
        if (beanName.equals("orderService")) {
            OrderService orderService = (OrderService) bean;
            System.out.println("Bean初始化结束。。。name为。。。" + orderService.getName());
        }
        return bean;
    }
}

 

 扫描

 

 

 

 

package spring;

import annotiton.*;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

public class CharkeyApplicationContext {

    private Class appConfig;

    private static ConcurrentHashMap<String, BeanDefinition> beanDifinitionMap = new ConcurrentHashMap<>();

    private static ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();

    private static List<BeanPostProcessor> listBean = new ArrayList<>();

    public CharkeyApplicationContext(Class configClass) {
        this.appConfig = appConfig;

        //扫描bean
        scan(configClass);

        beanDifinitionMap.forEach((beanName, clazz) -> {
            String scope = clazz.getScope();
            if (scope.equals("singleton")) {
                Object bean = createBean(beanName, clazz);
                singletonObjects.put(beanName, bean);
            }
        });
    }

    public Object getBean(String name) {
        BeanDefinition beanDefinition = beanDifinitionMap.get(name);
        String scope = beanDefinition.getScope();
        if (scope.equals("prototype")) return createBean(name, beanDefinition);
        return singletonObjects.get(name);
    }

    public Object createBean(String beanName, BeanDefinition beanDefinition) {
        Class clazz = beanDefinition.getClazz();

        try {
            Object o = clazz.getDeclaredConstructor().newInstance();

            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field field : declaredFields) {
                boolean annotationPresent = field.isAnnotationPresent(Autowired.class);
                if (annotationPresent) {
                    Autowired autowired = (Autowired) clazz.getDeclaredAnnotation(Autowired.class);
                    if (autowired == null) continue;
                    boolean requied = autowired.value();
                    if (requied && o == null) throw new RuntimeException("没有找到bean");
                    Object bean = getBean(field.getName());
                    field.setAccessible(true);
                    field.set(o, bean);
                }
            }
            //初始化前执行
            for (BeanPostProcessor processor : listBean) {
                processor.postProcessorBeforeInintion(beanName,o);
            }

            //初始化执行
            if (o instanceof InitializingBean) {
                ((InitializingBean) o).afterPropertiesSet();
            }

            //初始化前执行
            for (BeanPostProcessor processor : listBean) {
                processor.postProcessorAfterInintion(beanName,o);
            }
            return o;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public void scan(Class app) {

        boolean annotationPresent = app.isAnnotationPresent(ComponentScan.class);
        if (!annotationPresent) throw new RuntimeException("没有配置类");

        ComponentScan componentScan = (ComponentScan) app.getDeclaredAnnotation(ComponentScan.class);
        String path = componentScan.value();
        System.out.println(path);

        ClassLoader classLoader = CharkeyApplicationContext.class.getClassLoader();
        path = path.replace(".", "/");
        System.out.println(path);
        URL resource = classLoader.getResource("service/impl");//"com/charkey/service"
        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (int i = 0; i < files.length; i++) {
                File file1 = files[i];
                String absolutePath = file1.getAbsolutePath();
                System.out.println(absolutePath);
                absolutePath = absolutePath.substring(absolutePath.indexOf("service"), absolutePath.indexOf(".class"));
                System.out.println(absolutePath);
                absolutePath = absolutePath.replace("\\", ".");
                System.out.println(absolutePath);

                Class<?> clazz = null;
                try {
                    clazz = classLoader.loadClass(absolutePath);

                    boolean isComponent = clazz.isAnnotationPresent(Component.class);
                    if (!isComponent) continue;
                    Component declaredAnnotation = clazz.getDeclaredAnnotation(Component.class);
                    String beanName = declaredAnnotation.value();

                    if (BeanPostProcessor.class.isAssignableFrom(clazz)) {//MyBeanPostInitialization
                        BeanPostProcessor beanPostProcessor = (BeanPostProcessor) clazz.getDeclaredConstructor().newInstance();
                        listBean.add(beanPostProcessor);
                    }

                    if((clazz.getName()).indexOf("MyBeanPostInitialization") > 0)continue;
                    if((beanName == null || beanName.equals("")) ){

                        beanName = clazz.getName().substring(clazz.getName().lastIndexOf(".")+1);

                        beanName = Character.toLowerCase(beanName.charAt(0)) +
                                (beanName.length() > 1 ? beanName.substring(1) :"");

                        beanName = beanName.replace("Impl","");
                    }

                    String scopeVal = "singleton";//默认单例Bean
                    boolean isScope = clazz.isAnnotationPresent(Scope.class);
                    if (isScope) {
                        Scope scope1 = clazz.getDeclaredAnnotation(Scope.class);
                        scopeVal = scope1.value();
                    }

                    BeanDefinition beanDefinition = new BeanDefinition();
                    beanDefinition.setClazz(clazz);
                    beanDefinition.setScope(scopeVal);
                    beanDifinitionMap.put(beanName, beanDefinition);

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

                if (clazz != null && clazz.isAnnotationPresent(Component.class)) {
                    System.out.println(absolutePath);
                }
            }
        }

    }
}

 五.实现AOP

在Bean初始化完成后,配置JDK的Proxy对象并返回

package service.impl;

import annotiton.BeanPostProcessor;
import annotiton.Component;
import service.OrderService;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

@Component
public class MyBeanPostInitialization implements BeanPostProcessor {
    @Override
    public Object postProcessorBeforeInintion(String beanName, Object bean) {
        if (beanName.equals("orderService")) {
            OrderService orderService = (OrderService) bean;
            System.out.println("Bean开始初始化。。。");
            orderService.setName("charkey");
        }
        return bean;
    }

    @Override
    public Object postProcessorAfterInintion(String beanName, Object bean) {
        if (beanName.equals("orderService")) {
            OrderService orderService = (OrderService) bean;
            System.out.println("Bean初始化结束。。。name为。。。" + orderService.getName());

            Object proxyInstance = Proxy.newProxyInstance(MyBeanPostInitialization.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("执行test方法前AOP执行逻辑。。。。。");
                    return method.invoke(bean, args);
                }
            });

            return proxyInstance;
        }
        return bean;
    }
}

 

 

 

posted @ 2023-03-14 14:56  蔡徐坤1987  阅读(26)  评论(0编辑  收藏  举报