Spring源码深度解析:二、手写模拟Spring

一、前言

  1. 文章目录:Spring源码深度解析:文章目录
  2. 参考文档
  3. 如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正

二、手写模拟Spring

我们在学习Spring源码之前,我们先整体的了解一下Spring容器由哪些组成,主要是由于IOC和AOP构成。
在这里插入图片描述
然后自己先模拟手写一下Spring容器的整体架构,这样通过简单地demo让我们更加通俗的理解一个Spring容器主要做了哪些事情。方便为我们后面学习Spring源码。

1、Spring框架初始化结构

  1. 创建两个包名
    在这里插入图片描述

  2. 创建启动类
    添加“com.wts.spring.WtsApplicationContext”类,代码如下:

    /**
     * 启动类
     */
    public class WtsApplicationContext {
    
    }
    
  3. 创建一个业务类和测试类:
    业务类
    添加“com.wts.service.UserService”类,代码如下:

    public class UserService {
    }
    
    

    测试类
    添加“com.wts.service.Test”类,代码如下:

    public class Test {
    	public static void main(String[] args) {
    	
    	}
    }
    
  4. 创建一个配置类
    添加“com.wts.service.AppConfig”类,代码如下:

    /**
     * 配置类
     */
    public class AppConfig {
    
    }
    
  5. 创建一个ComponentScan扫描注解
    添加“com.wts.spring.ComponentScan”类,代码如下:

    @Retention修饰注解,用来表示注解的生命周期; RetentionPolicy.RUNTIME 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在; 运行时也存在; 需要在运行时去动态获取注解信息
    @Target:注解的作用目标; ElementType.TYPE:指定到接口、类、枚举、注解上

    /**
     * 扫描注解
     */
    @Retention(RetentionPolicy.RUNTIME) // @Retention修饰注解,用来表示注解的生命周期; RetentionPolicy.RUNTIME 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在; 运行时也存在; 需要在运行时去动态获取注解信息
    @Target({ElementType.TYPE}) //@Target:注解的作用目标; ElementType.TYPE:指定到接口、类、枚举、注解上
    public @interface ComponentScan {
    
        String value() default "";
    }
    
  6. 创建一个Componet注解
    添加“com.wts.spring.Component”类,代码如下:

    /**
     * 配置注解
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE}) 
    public @interface Component {
    
        String value() default "";
    }
    
  7. 配置类扫描service类
    修改“com.wts.service.AppConfig”类,代码如下:

    /**
     * 配置类
     */
    @ComponentScan("com.wts.service")
    public class AppConfig {
    }
    
  8. 业务类添加@Componet注解
    修改“com.wts.service.UserService”类,代码如下:

    @Component("userService")
    public class UserService {
    }
    
  9. 启动类添加configClass属性,并且创建一个获取Bean方法
    修改“com.wts.spring.WtsApplicationContext”类,代码如下:

    public class WtsApplicationContext {
    
        private Class configClass;
    
        public WtsApplicationContext(Class configClass) {
            this.configClass = configClass;
        }
        
        /**
         * 获取Bean
         *
         * @param beanName
         * @return
         */
        public Object getBean(String beanName){
            return null;
        }
    }
    
  10. 测试类进行测试
    修改“com.wts.service.Test”类,代码如下:

    public class Test {
        public static void main(String[] args) {
    
            WtsApplicationContext applicationContext = new WtsApplicationContext(AppConfig.class);
    
            UserService userService = (UserService) applicationContext.getBean("userService");
        }
    }
    

    【结果】
    在这里插入图片描述
    从结果我们可以看到获取的bean为null,那是因为我们虽然配置了扫描注解和配置注解,但是我们没有实现这些注解,接下来让我们去实现扫描注解,使得注解生效。

2、Spring扫描(ComponentScan)底层实现

修改“com.wts.spring.WtsApplicationContext”类,代码如下:

public class WtsApplicationContext {

    private Class configClass;

    public WtsApplicationContext(Class configClass) {
        this.configClass = configClass;

        // 扫描
        // 判断该类有没有ComponentScan注解
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            // 拿到ComponentScan注解
            ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            // 扫描路径 com.wts.service(这个只是包名,下面一步转化成路径名)
            String path = componentScanAnnotation.value();
            String path1 = path.replace(".", "/"); // com/wts/service(相对路径)
            // 获取类加载器
            ClassLoader classLoader = WtsApplicationContext.class.getClassLoader();
            URL resource = classLoader.getResource(path1);
            System.out.println("URL:" + resource);
            // 获取file对象 通过相对路径拿到正确的文件路径
            File file = new File(resource.getFile());
            System.out.println("file对象:" + file);
            // 判断file是不是一个文件夹
            if (file.isDirectory()) {
                // 拿到当前文件夹的所有文件
                File[] files = file.listFiles();
                for (File f : files) {
                    // 拿到文件的绝对路径
                    String fileName = f.getAbsolutePath();
                    System.out.println("绝对路径:" + fileName);
                    if (fileName.endsWith(".class")) {
                        // com\wts\service\UserService
                        String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
                        // 类名
                        className = className.replace("\\", ".");
                        System.out.println("类名:" + className);
                        try {
                            // Class对象
                            Class<?> clazz = classLoader.loadClass(className);
                            if (clazz.isAnnotationPresent(Component.class)) {
                                // Bean
                            }
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    public Object getBean(String beanName) {
        return null;
    }
}

【结果】
在这里插入图片描述
现在我们已经实现了@ComponentScan注解的功能,获取到了bean对象的类名和类路径。这一功能我们虽然获取到了这个bean类的信息,但是我们getBean()方法还是不能拿到该bean的信息,这时候我们就想想应该怎么拿到@ComponentScan注解获取到的信息呢,我们就想到等@ComponentScan注解底层实现获取这些bean信息的时候先把它缓存起来,然后需要这些信息的时候,我们再调用就好了,所以接下来我们就继续按照我们的思路继续实现。先定义一个bean信息的封装类,然后缓存起来。

因为spring的对象有可能是单例模式的(默认都是单例的),也有可能是原型模式的,所以我们的bean的封装类定义两个属性

  • type:Class对象
  • scope:范围(简单说就是对象在spring容器(IOC容器)中的生命周期,也可以理解为对象在spring容器中的创建方式。)

3、手写模拟BeanDefinition的生成

  1. 创建BeanDefinition
    添加“com.wts.spring.BeanDefinition”类,代码如下:

    public class BeanDefinition {
    
        /**
         * Class对象
         */
        private Class type;
    
        /**
         * 范围(简单说就是对象在spring容器(IOC容器)中的生命周期,也可以理解为对象在spring容器中的创建方式。)
         */
        private String scope;
    
    
    
        public Class getType() {
            return type;
        }
    
        public void setType(Class type) {
            this.type = type;
        }
    
        public String getScope() {
            return scope;
        }
    
        public void setScope(String scope) {
            this.scope = scope;
        }
    }
    
  2. 创建Scope注解
    添加“com.wts.spring.Scope”类,代码如下:

    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 Scope {
    
        String value() default "";
    
    }
    
  3. 启动类修改
    修改“com.wts.spring.WtsApplicationContext”类,代码如下:

    public class WtsApplicationContext {
    
        private Class configClass;
    
        // beanDefinition内存
        private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    
        public WtsApplicationContext(Class configClass) {
            this.configClass = configClass;
    
            // 1、扫描 --> BeanDefinition --> beanDefinitionMap
            // 判断该类有没有ComponentScan注解
            if (configClass.isAnnotationPresent(ComponentScan.class)) {
                // 拿到ComponentScan注解
                ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
                // 扫描路径 com.wts.service(这个只是包名,下面一步转化成路径名)
                String path = componentScanAnnotation.value();
                String path1 = path.replace(".", "/"); // com/wts/service(相对路径)
                // 获取类加载器
                ClassLoader classLoader = WtsApplicationContext.class.getClassLoader();
                URL resource = classLoader.getResource(path1);
                System.out.println("URL:" + resource);
                // 获取file对象 通过相对路径拿到正确的文件路径
                File file = new File(resource.getFile());
                System.out.println("file对象:" + file);
                // 判断file是不是一个文件夹
                if (file.isDirectory()) {
                    // 拿到当前文件夹的所有文件
                    File[] files = file.listFiles();
                    for (File f : files) {
                        // 拿到文件的绝对路径
                        String fileName = f.getAbsolutePath();
                        System.out.println("绝对路径:" + fileName);
                        if (fileName.endsWith(".class")) {
                            // com\wts\service\UserService
                            String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
                            // 类名
                            className = className.replace("\\", ".");
                            System.out.println("类名:" + className);
                            try {
                                // Class对象
                                Class<?> clazz = classLoader.loadClass(className);
                                if (clazz.isAnnotationPresent(Component.class)) {
                                    // 获取Component注解
                                    Component component = clazz.getAnnotation(Component.class);
                                    // 拿到beanName
                                    String beanName = component.value();
                                    // 如果Componnet注解没有定义beanName,默认类第一个首字母小写的beanName
                                    if (beanName.equals("")){
                                        beanName = Introspector.decapitalize(clazz.getSimpleName());
                                    }
                                    // 创建BeanDefinition对象
                                    BeanDefinition beanDefinition = new BeanDefinition();
                                    // BeanDefinition对象初始化类型字段
                                    beanDefinition.setType(clazz);
                                    // 判断是否有Scope注解, 如果有Scope注解,拿到Scope的值放到BeanDefinition对象的scope属性上;没有默认是单例
                                    if (clazz.isAnnotationPresent(Scope.class)) {
    
                                        Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
                                        beanDefinition.setScope(scopeAnnotation.value());
                                    } else {
                                        beanDefinition.setScope("singleton");
                                    }
    
                                    beanDefinitionMap.put(beanName, beanDefinition);
                                }
                            } catch (ClassNotFoundException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }    
    
        public Object getBean(String beanName) {
            return null;
        }
    }
    

    【结果】
    在这里插入图片描述
    我们可以看到已经把获取到的bean信息缓存起来了,下面就让我们实现如何获取bean信息

4、手写模拟getBean()方法的底层实现

修改“com.wts.spring.WtsApplicationContext”类,代码如下:

public class WtsApplicationContext {

    private Class configClass;

    // beanDefinition内存
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    
    // 单例池
    private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();

    /**
     * spring容器构造方法
     *
     * @param configClass
     */
    public WtsApplicationContext(Class configClass) {
        this.configClass = configClass;

        // 1、扫描 --> BeanDefinition --> beanDefinitionMap
        // 判断该类有没有ComponentScan注解
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            // 拿到ComponentScan注解
            ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            // 扫描路径 com.wts.service(这个只是包名,下面一步转化成路径名)
            String path = componentScanAnnotation.value();
            String path1 = path.replace(".", "/"); // com/wts/service(相对路径)
            // 获取类加载器
            ClassLoader classLoader = WtsApplicationContext.class.getClassLoader();
            URL resource = classLoader.getResource(path1);
            System.out.println("URL:" + resource);
            // 获取file对象 通过相对路径拿到正确的文件路径
            File file = new File(resource.getFile());
            System.out.println("file对象:" + file);
            // 判断file是不是一个文件夹
            if (file.isDirectory()) {
                // 拿到当前文件夹的所有文件
                File[] files = file.listFiles();
                for (File f : files) {
                    // 拿到文件的绝对路径
                    String fileName = f.getAbsolutePath();
                    System.out.println("绝对路径:" + fileName);
                    if (fileName.endsWith(".class")) {
                        // com\wts\service\UserService
                        String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
                        // 类名
                        className = className.replace("\\", ".");
                        System.out.println("类名:" + className);
                        try {
                            // Class对象
                            Class<?> clazz = classLoader.loadClass(className);
                            if (clazz.isAnnotationPresent(Component.class)) {
                                // 获取Component注解
                                Component component = clazz.getAnnotation(Component.class);
                                // 拿到beanName
                                String beanName = component.value();
                                // 如果Componnet注解没有定义beanName,默认类第一个首字母小写的beanName
                                if (beanName.equals("")){
                                    beanName = Introspector.decapitalize(clazz.getSimpleName());
                                }
                                // 创建BeanDefinition对象
                                BeanDefinition beanDefinition = new BeanDefinition();
                                // BeanDefinition对象初始化类型字段
                                beanDefinition.setType(clazz);
                                // 判断是否有Scope注解, 如果有Scope注解,拿到Scope的值放到BeanDefinition对象的scope属性上;没有默认是单例
                                if (clazz.isAnnotationPresent(Scope.class)) {

                                    Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
                                    beanDefinition.setScope(scopeAnnotation.value());
                                } else {
                                    beanDefinition.setScope("singleton");
                                }

                                beanDefinitionMap.put(beanName, beanDefinition);
                                System.out.println("beanDefinitionMap:" + beanDefinitionMap);
                            }
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        // 2、实例化单例Bean
        for (String beanName : beanDefinitionMap.keySet()) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            if (beanDefinition.getScope().equals("singleton")) {
                Object bean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName, bean);
            }
        }
    }

    /**
     * 创建bean
     * 
     * @param beanName
     * @param beanDefinition
     * @return
     */
    private Object createBean(String beanName, BeanDefinition beanDefinition) {
        return null;
    }

     /**
     * 获取Bean
     *
     * @param beanName
     * @return
     */
    public Object getBean(String beanName) {
        // 根据map获取BeanDefinition对象
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);

        if (beanDefinition == null) {
            throw new NullPointerException();
        } else {
            String scope = beanDefinition.getScope();
            if (scope.equals("singleton")) {
                // 去单例池里面拿bean对象,如果没有就创建Bean对象,并放到单例池中
                Object bean = singletonObjects.get(beanName);
                    if (bean == null) {
                        Object o = createBean(beanName, beanDefinition);
                        singletonObjects.put(beanName, o);
                    }
                return bean;
            } else {
                // 多例 直接每一次创建bean对象
                return createBean(beanName, beanDefinition);
            }
        }
    }
}

5、手写模拟Bean的创建流程

	/**
     * 创建bean
     *
     * @param beanName
     * @param beanDefinition
     * @return
     */
    private Object createBean(String beanName, BeanDefinition beanDefinition) {
        // 当前bean对应的类
        Class clazz = beanDefinition.getType();
        try {
            // 通过类的无参构造方法生成一个实例对象
            Object instance = clazz.getConstructor().newInstance();
            for (Field field : clazz.getDeclaredFields()) {
            
            }
            return instance;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

测试

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

        WtsApplicationContext applicationContext = new WtsApplicationContext(AppConfig.class);

//        UserService userService = (UserService) applicationContext.getBean("userService");

        System.out.println(applicationContext.getBean("userService"));
        System.out.println(applicationContext.getBean("userService"));
        System.out.println(applicationContext.getBean("userService"));
        System.out.println(applicationContext.getBean("userService"));
    }
}

【结果】
1、输出为同一个对象,是单例bean
在这里插入图片描述
2、将UserService变为多例对象,输出结果为4个不同对象
在这里插入图片描述

6、手写模拟依赖注入

在Spring容器中修改以下代码,这样我们在使用Component注解的时候,默认给我们命名的类名为首字母小写的类
在这里插入图片描述

  1. 创建@Autowired注解
    添加“com.wts.spring.Autowired”类,代码如下:

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface Autowired {
    
    }
    
  2. 创建OrderService
    添加“com.wts.service.OrderService”类,代码如下:

    @Component
    public class OrderService {
    
    }
    
  3. UserService注入OrderService类
    修改“com.wts.service.UserService”类,代码如下:

    @Component("userService")
    public class UserService {
    
        @Autowired
        private OrderService orderService;
    
        public void test(){
            System.out.println(orderService);
        }
    }
    
  4. 测试
    修改“com.wts.service.Test”类,代码如下:

    public class Test {
        public static void main(String[] args) {
    
            WtsApplicationContext applicationContext = new WtsApplicationContext(AppConfig.class);
    
            UserService userService = (UserService) applicationContext.getBean("userService");
    
            userService.test();
        }
    }
    

    发现查出结果为null
    在这里插入图片描述

  5. 修改Spring容器的创建Bean方法:在创建bean对象的时候,为实例对象设置Autowired对象标注的类
    修改“com.wts.spring.WtsApplicationContext”类,代码如下:

     /**
         * 创建bean
         *
         * @param beanName
         * @param beanDefinition
         * @return
         */
        private Object createBean(String beanName, BeanDefinition beanDefinition) {
            // 当前bean对应的类
            Class clazz = beanDefinition.getType();
            try {
                // 通过类的无参构造方法生成一个实例对象
                Object instance = clazz.getConstructor().newInstance();
                // 依赖注入
                for (Field field : clazz.getDeclaredFields()) {
                    if (field.isAnnotationPresent(Autowired.class)) {
                        // 反射类中的setAccessible是启用和禁用访问安全检查的开关,
                        field.setAccessible(true);
                        field.set(instance, getBean(field.getName()));
                    }
                }
                return instance;
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            return null;
        }
    

    【结果】
    在这里插入图片描述

7、手写模拟Aware回调机制

  1. 创建BeanNameAware接口
    添加“com.wts.spring.BeanNameAware”类,代码如下:
    public interface BeanNameAware {
    
        public void setBeanName(String beanName);
    }
    
  2. 修改Spring容器的createBean()方法
    修改“com.wts.spring.WtsApplicationContext”类,代码如下:
     	/**
         * 创建bean
         *
         * @param beanName
         * @param beanDefinition
         * @return
         */
        private Object createBean(String beanName, BeanDefinition beanDefinition) {
            // 当前bean对应的类
            Class clazz = beanDefinition.getType();
            try {
                // 通过类的无参构造方法生成一个实例对象
                Object instance = clazz.getConstructor().newInstance();
                // 依赖注入
                for (Field field : clazz.getDeclaredFields()) {
                    if (field.isAnnotationPresent(Autowired.class)) {
                        // 反射类中的setAccessible是启用和禁用访问安全检查的开关,
                        field.setAccessible(true);
                        field.set(instance, getBean(field.getName()));
                    }
                }
    
                // Aware回调
                if (instance instanceof BeanNameAware){
                    ((BeanNameAware) instance).setBeanName(beanName);
                }
                return instance;
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            return null;
        }
    
  3. 修改UserService类
    修改“com.wts.service.UserService”类,代码如下:
    @Component("userService")
    public class UserService implements BeanNameAware {
    
        @Autowired
        private OrderService orderService;
    
        private String beanName;
    
        public void test(){
            System.out.println(orderService);
        }
    
        @Override
        public void setBeanName(String beanName) {
            this.beanName = beanName;
        }
    }
    

8、手写模拟Spring初始化机制

  1. 创建InitializingBean接口
    添加“com.wts.spring.InitializingBean”类,代码如下:
    public interface InitializingBean {
    
        public void afterPropertiesSet();
    }
    
  2. 修改spring容器的createBean()方法
    修改“com.wts.spring.WtsApplicationContext”类,代码如下:
    /**
         * 创建bean
         *
         * @param beanName
         * @param beanDefinition
         * @return
         */
        private Object createBean(String beanName, BeanDefinition beanDefinition) {
            // 当前bean对应的类
            Class clazz = beanDefinition.getType();
            try {
                // 通过类的无参构造方法生成一个实例对象
                Object instance = clazz.getConstructor().newInstance();
                // 依赖注入
                for (Field field : clazz.getDeclaredFields()) {
                    if (field.isAnnotationPresent(Autowired.class)) {
                        // 反射类中的setAccessible是启用和禁用访问安全检查的开关,
                        field.setAccessible(true);
                        field.set(instance, getBean(field.getName()));
                    }
                }
    
                // Aware回调
                if (instance instanceof BeanNameAware){
                    ((BeanNameAware) instance).setBeanName(beanName);
                }
    
                // 初始化
                if (instance instanceof InitializingBean){
                    ((InitializingBean) instance).afterPropertiesSet();
                }
    
                // BeanPostProcessor 初始化后 AOP
                return instance;
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            return null;
        }
    
  3. 修改UserService类
    修改“com.wts.service.UserService”类,代码如下:
    @Component("userService")
    public class UserService implements BeanNameAware, InitializingBean {
    
        @Autowired
        private OrderService orderService;
    
        private String beanName;
    
        private String xxx;
    
        public void test(){
            System.out.println(orderService);
        }
    
        @Override
        public void setBeanName(String beanName) {
            this.beanName = beanName;
        }
    
        @Override
        public void afterPropertiesSet() {
            //。。。。。。。。
            System.out.println("初始化方法");
        }
    }
    

9、手写模拟BeanPostProcessor机制

  1. 创建BeanPostProcessor接口
    添加“com.wts.spring.BeanPostProcessor”类,代码如下:

    public interface BeanPostProcessor {
    
        public void postProcessBeforeInitialization(String beanName, Object bean);
    
        public void postProcessAfterInitialization(String beanName, Object bean);
    }
    
  2. 修改spring容器的createBean()方法
    修改“com.wts.service.UserService”类,代码如下:

    /**
         * 创建bean
         *
         * @param beanName
         * @param beanDefinition
         * @return
         */
        private Object createBean(String beanName, BeanDefinition beanDefinition) {
            // 当前bean对应的类
            Class clazz = beanDefinition.getType();
            try {
                // 通过类的无参构造方法生成一个实例对象
                Object instance = clazz.getConstructor().newInstance();
                // 依赖注入
                for (Field field : clazz.getDeclaredFields()) {
                    if (field.isAnnotationPresent(Autowired.class)) {
                        // 反射类中的setAccessible是启用和禁用访问安全检查的开关,
                        field.setAccessible(true);
                        field.set(instance, getBean(field.getName()));
                    }
                }
    
                // Aware回调
                if (instance instanceof BeanNameAware){
                    ((BeanNameAware) instance).setBeanName(beanName);
                }
    
                // 初始化前
                for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                    beanPostProcessor.postProcessBeforeInitialization(beanName, instance);
                }
    
                // 初始化
                if (instance instanceof InitializingBean){
                    ((InitializingBean) instance).afterPropertiesSet();
                }
    
                // 初始化后
                for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                    beanPostProcessor.postProcessAfterInitialization(beanName, instance);
                }
    
                // BeanPostProcessor 初始化后 AOP
                return instance;
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            return null;
        }
    
  3. 创建WtsBeanPostProcessor类
    修改“com.wts.service.WtsBeanPostProcessor”类,代码如下:

    @Component
    public class WtsBeanPostProcessor implements BeanPostProcessor {
        @Override
        public void postProcessBeforeInitialization(String beanName, Object bean) {
            if (beanName.equals("userService")) {
                System.out.println("111111");
            }
        }
    
        @Override
        public void postProcessAfterInitialization(String beanName, Object bean) {
            if (beanName.equals("userService")) {
                System.out.println("222222");
            }
        }
    }
    
  4. 测试
    修改“com.wts.service.Test”类,代码如下

    public class Test {
        public static void main(String[] args) {
    
            WtsApplicationContext applicationContext = new WtsApplicationContext(AppConfig.class);
    
            UserService userService = (UserService) applicationContext.getBean("userService");
    
            userService.test();
        }
    }
    

    【结果】
    在这里插入图片描述

10、手写模拟AOP机制

  1. 修改BeanPostProcessor
    修改“com.wts.spring.BeanPostProcessor”类,代码如下:

    public interface BeanPostProcessor {
    
        public Object postProcessBeforeInitialization(String beanName, Object bean);
    
        public Object postProcessAfterInitialization(String beanName, Object bean);
    }
    
  2. 修改spring容器的createBean()方法
    修改“com.wts.spring.WtsApplicationContext”类,代码如下:

    /**
         * 创建bean
         *
         * @param beanName
         * @param beanDefinition
         * @return
         */
        private Object createBean(String beanName, BeanDefinition beanDefinition) {
            // 当前bean对应的类
            Class clazz = beanDefinition.getType();
            try {
                // 通过类的无参构造方法生成一个实例对象
                Object instance = clazz.getConstructor().newInstance();
                // 依赖注入
                for (Field field : clazz.getDeclaredFields()) {
                    if (field.isAnnotationPresent(Autowired.class)) {
                        // 反射类中的setAccessible是启用和禁用访问安全检查的开关,
                        field.setAccessible(true);
                        field.set(instance, getBean(field.getName()));
                    }
                }
    
                // Aware回调
                if (instance instanceof BeanNameAware){
                    ((BeanNameAware) instance).setBeanName(beanName);
                }
    
                // 初始化前
                for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                    instance = beanPostProcessor.postProcessBeforeInitialization(beanName, instance);
                }
    
                // 初始化
                if (instance instanceof InitializingBean){
                    ((InitializingBean) instance).afterPropertiesSet();
                }
    
                // 初始化后
                for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                    instance = beanPostProcessor.postProcessAfterInitialization(beanName, instance);
                }
    
                // BeanPostProcessor 初始化后 AOP
                return instance;
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            return null;
        }
    
  3. 创建UserInterface接口
    添加“com.wts.service.UserInterface”类,代码如下:

    public interface UserInterface {
    
        public void test();
    }
    
  4. 修改UserService类
    修改“com.wts.service.UserService”类,代码如下:

    @Component("userService")
    public class UserService implements BeanNameAware, InitializingBean, UserInterface {
    
        @Autowired
        private OrderService orderService;
    
        private String beanName;
    
        private String xxx;
    
        @Override
        public void test(){
            System.out.println(orderService);
        }
    
        @Override
        public void setBeanName(String beanName) {
            this.beanName = beanName;
        }
    
        @Override
        public void afterPropertiesSet() {
            //。。。。。。。。
            System.out.println("初始化方法");
        }
    }
    
  5. 修改WtsBeanPostProcessor类
    修改“com.wts.service.WtsBeanPostProcessor”类,代码如下:

    @Component
    public class WtsBeanPostProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(String beanName, Object bean) {
            if (beanName.equals("userService")) {
                System.out.println("111111");
            }
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(String beanName, Object bean) {
            if (beanName.equals("userService")) {
                System.out.println("222222");
                Object proxyInstance = Proxy.newProxyInstance(WtsBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("切面逻辑");
                        return method.invoke(bean, args);
                    }
                });
                return proxyInstance;
            }
    
            return bean;
    
        }
    }
    
  6. 测试:
    修改“com.wts.service.Test”类,代码如下:

    public class Test {
        public static void main(String[] args) {
    
            WtsApplicationContext applicationContext = new WtsApplicationContext(AppConfig.class);
    
            UserService userService = (UserService) applicationContext.getBean("userService");
    
            userService.test();
        }
    }
    

    【结果】:
    在这里插入图片描述

    修改测试方法
    在这里插入图片描述

    【结果】
    在这里插入图片描述

三、手写模拟Bean的生命周期

1、创建Bean的生命周期

UserService---->推断构造---->普通对象----->依赖注入---->初始化前(@PostConstruct)----->初始化(InitializingBean)---->初始化后(AOP)---->代理对象-----> 放入Map单例池中---->Bean对象

2、创建一个modle: spring-hello

在这里插入图片描述

  1. 创建OrderService业务类
    添加“com.wts.service.OrderService”类,代码如下:

    @Component
    public class OrderService {
    
    }
    
  2. 创建一个UserService 类
    添加“com.wts.service.UserService ”类,代码如下:

    @Component
    public class UserService {
    
    	@Autowired
    	private OrderService orderService;
    
    	public void test(){
    		System.out.println(orderService);
    	}
    }
    
  3. 创建一个AppConfig配置类
    添加“com.wts.AppConfig”类,代码如下:

    @ComponentScan("com.wts")
    public class AppConfig {
    }
    
  4. 创建测试类
    添加“com.wts.Test”类,代码如下:

    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
    		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
    		UserService userService = (UserService) applicationContext.getBean("userService");
    		userService.test();
    }
    

    测试:
    在这里插入图片描述

3、具体实现

  1. 普通对象

在test的main方法里实例化UserService对象

UserService userService1 = new UserService();
  1. 依赖注入

判断当前属性是否有Autowired注解,给当前属性赋值

public class Test {

	public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();

		/**
		 * 创建
		 * UserService---->推断构造---->普通对象----->依赖注入---->初始化前(@PostConstruct)
		 * ----->初始化(InitializingBean)---->初始化后(AOP)---->代理对象-----> 放入Map单例池中---->Bean对象
		 */

		UserService userService1 = new UserService();
		
		// 依赖注入实现
		// 获取对象的所有属性
        for (Field field : userService1.getClass().getDeclaredFields()) {
            // 判断当前属性是否有Autowired注解
            if (field.isAnnotationPresent(Autowired.class)) {
                // 给当前属性赋值
                field.set(userService1, ??);
            }
        }
}
  1. 初始化前
    创建一个User类
    添加“com.wts.service.User”类,代码如下:

    public class User {
    }
    

    修改UserService类中代码:admin属性不通过@Autowired注解注入,而是创建一个a()方法,并在方法上加上@PostConstruct注解

    @Component
    public class UserService {
    
    	@Autowired
    	private OrderService orderService;
    
    //	@Autowired
    	private User admin;   // new User();
    
    	@PostConstruct
    	public void a(){
    		// mysql--->管理员的数据--->User对象---->this.admin
    	}
    	public void test(){
    		System.out.println(orderService);
    	}
    }
    

    test中的main方法简写初始化前如何实现

    public class Test {
    
    	public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
    		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
    		UserService userService = (UserService) applicationContext.getBean("userService");
    		userService.test();
    
    		/**
    		 * 创建
    		 * UserService---->推断构造---->普通对象----->依赖注入---->初始化前(@PostConstruct)
    		 * ----->初始化(InitializingBean)---->初始化后(AOP)---->代理对象-----> 放入Map单例池中---->Bean对象
    		 */
    
    		UserService userService1 = new UserService();
    
    		// 依赖注入实现
    		// 获取对象的所有属性
    //        for (Field field : userService1.getClass().getDeclaredFields()) {
    //            // 判断当前属性是否有Autowired注解
    //            if (field.isAnnotationPresent(Autowired.class)) {
    //                // 给当前属性赋值
    //                field.set(userService1, ??);
    //            }
    //        }
    
    		// 初始化前
    		// 获取当前对象的所有方法
    		for (Method method : userService1.getClass().getDeclaredMethods()) {
    			// 判断当前方法是否有PostConstruct注解
    			if (method.isAnnotationPresent(PostConstruct.class)){
    				method.invoke(userService1, null);
    			}
    		}
    	}
    }
    
  2. 初始化
    UserService类实现spring自带的InitializingBean接口,并继承afterPropertiesSet()方法,并通过该方法对admin属性进行赋值

    @Component
    public class UserService implements InitializingBean {
    
    	@Autowired
    	private OrderService orderService;
    
    //	@Autowired
    	private User admin;   // new User();
    
    //	@PostConstruct
    	public void a(){
    		// mysql--->管理员的数据--->User对象---->this.admin
    	}
    	public void test(){
    		System.out.println(orderService);
    	}
    
    	@Override
    	public void afterPropertiesSet() throws Exception {
    		// mysql--->管理员的数据--->User对象---->this.admin
    	}
    }
    
  3. 推断构造
    spring先通过类型查找Bean(byType)–>类型没有再通过bean名字查找Bean(byName) 单例池Map<beanName, Bean对象>
    1、创建OrderService类的名字为orderService

    @Component
    public class OrderService {  // orderService
    
    }
    

    2、创建OrderService类的名字分别为orderService1、orderService2

    @ComponentScan("com.wts")
    public class AppConfig {
    
    	@Bean
    	public OrderService orderService1(){
    		return new OrderService();
    	}
    
    	@Bean
    	public OrderService orderService2(){
    		return new OrderService();
    	}
    }
    

    测试

    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
    		System.out.println(applicationContext.getBean("orderService"));
    		System.out.println(applicationContext.getBean("orderService1"));
    		System.out.println(applicationContext.getBean("orderService2"));
    }
    

    在这里插入图片描述

  4. AOP
    UserService类:com.wts.service.UserService

    @Component
    public class UserService {
    
    	@Autowired
    	private OrderService orderService;
    
    	public void test(){
    		System.out.println(orderService);
    	}
    }
    

    OrderService类:com.wts.service.OrderService

    @Component
    public class OrderService {  // orderService
    
    }
    

    创建切面WtsAspect:com.wts.aspect.WtsAspect

    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Component
    public class WtsAspect {
    
    	@Before("execution(public void com.wts.service.UserService.test())")
    	public void wtsBefore(){
    		System.out.println("wtsBefore");
    	}
    }
    

    打开AOP

    @ComponentScan("com.wts")
    @EnableAspectJAutoProxy  // 打开AOP
    public class AppConfig {
    
    }
    

    在这里插入图片描述

    UserServiceProxy对象---->UserService代理对象---->UserService代理对象.target=普通对象

    UserService代理对象.test()---->

    class UserServiceProxy extends UserService {
    	UserService target;
    	public void test(){
    		// @Before 增强逻辑
    		// target.test();  // 普通对象.test()
    	}
    }
    

    事务
    开启事务

    package com.wts;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.jdbc.datasource.DriverManagerDataSource;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    import javax.sql.DataSource;
    
    @ComponentScan("com.wts")
    @EnableTransactionManagement // 开启事务
    public class AppConfig {
    
    	@Bean
    	public JdbcTemplate jdbcTemplate() {
    		return new JdbcTemplate(datasource());
    	}
    
    	@Bean
    	public PlatformTransactionManager transactionManager() {
    		DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
    		transactionManager.setDataSource(datasource());
    		return transactionManager;
    	}
    
    	@Bean
    	public DataSource datasource(){
    		DriverManagerDataSource dataSource = new DriverManagerDataSource();
    		dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8&SSL=false");
    		dataSource.setUsername("root");
    		dataSource.setPassword("root");
    		return dataSource;
    	}
    }
    

    UserService执行sql

    @Component
    public class UserService {
    
    	@Autowired
    	private OrderService orderService;
    
    	@Autowired
    	private JdbcTemplate jdbcTemplate;
    
    	@Transactional
    	public void test(){
    		jdbcTemplate.execute("insert into t1 values (1, 1, 1, '1')");
    		throw new NullPointerException();
    	}
    }
    

    在这里插入图片描述
    事务管理器建立一个数据库连接conn ThreadLocal<Map<Datasource对象,数据库连接conn>>
    加上@Configuration注解 Appconfig产生一个动态代理对象,JdbcTemplate的dasource对象和transactionManager的datasource对象是同一个,因为都是代理对象在执行datasource()方法,会去ThreadLocal判断是否有,有直接取

    UserServiceProxy对象---->UserService代理对象---->UserService代理对象.target=普通对象

    UserService代理对象.test()---->

    class UserServiceProxy extends UserService {
    	UserService target;
    	public void test(){
    		// 有没有@Transactional
    		// 事务管理器建立一个数据库连接conn  ThreadLocal<Map<Datasource对象,数据库连接conn>>
    		// conn.autocommit = false
    		// target.test();  // 普通对象.test()
    		// connn.rollback()  conn.commit()
    	}
    }
    
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值