【Spring(七)】带你手写一个Spring容器

有关Spring的所有文章都收录于我的专栏:👉Spring👈
目录
前置准备
第一步、创建我们自定的注解
第二步、创建我们自己的容器类
测试
总结


相关文章

【Spring(一)】如何获取对象(Bean)【Spring(一)】如何获取对象(Bean)
【Spring(二)】java对象属性的配置(Bean的配置)【Spring(二)】java对象属性的配置(Bean的配置)
【Spring(三)】熟练掌握Spring的使用【Spring(三)】熟练掌握Spring的使用
【Spring(四)】Spring基于注解的配置方式【Spring(四)】Spring基于注解的配置方式
【Spring(五)】引入篇:AOP的底层原理之动态代理【Spring(五)】引入篇:AOP的底层原理之动态代理
【Spring(六)】使用篇:AOP在开发中的使用 【Spring(六)】使用篇:AOP在开发中的使用

前置准备

在此之前我们先的了解原生Spring容器中有什么,以及它们的功能都是什么,我们才能有目的实现它。我们先在Spring容器中注入一个Bean。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

第一步、创建我们自定的注解

@ComponentScan

这个注解用于标注配置类。我们手写的Spring容器使用的都是基于注解的方式。这个配置类就相当于我们的XML配置文件中配置扫描的包的路径。

package com.jl.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author long
 * @date 2022/9/4
 * @Target 指定我们的Component注解可以修饰Type程序元素
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
    String value() default "";
}

@Component

此注解用于标注Bean对象。我们这里只写一个@Component`,其他例如:@Service这些都是相同的原理。

package com.jl.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
    // 可以通过此注解指定bean的id值
    String value() default "";
}

@Scope

此注解用于声明Bean为单例还是多例。

package com.jl.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 可以指定bean的作用范围
 * singleton,prototype
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Scope {
    String value() default "";
}

@Autowired

用于自动装配的注解。

package com.jl.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
    // 可以通过此注解指定bean的id值
//    String value() default "";
}

@Aspect

用于标注切面类的注解。

package com.jl.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Aspect {
    String value() default "";
}

@Before

前置通知的注解。

package com.jl.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Before {
    String value();
    String argNames() default "";
}

@AfterReturning

返回通知的注解。

package com.jl.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AfterReturning {
    String value() default "";
    String pointcut() default "";
    String returning() default "";
    String argNames() default "";
}

@After

后置通知的注解。

package com.jl.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface After {
    String value();
    String argNames() default "";
}

第二步、创建我们自己的容器类

在【一】中我们可以看到原生Spring容器中有几个很重要的属性:

  1. beanDefinitionMap :用于存放Bean的配置信息。
  2. singletonObjects:存放创建好的Bean实例。
  3. beanPostProcessorList:我们这里再添加到一个存放后置处理器的数组。
private Class configClass;
// 定义属性BeanDefinitionMap->存放BeanDefinition对象
private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
// 定义属性SingletonObjects->存放单例对象
private ConcurrentHashMap<String,Object> singletonObjects= new ConcurrentHashMap<>();
// 定义属性,存放我们的后置处理器
private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();

扫描类

// 该方法完成对指定包的扫描,并将Bean信息封装到BeanDefinition对象,再放入Map中
public void beanDefinitionByScan(Class configClass){
   this.configClass = configClass;
   //1. 获取要扫描的包
   ComponentScan componentScan =
           (ComponentScan)this.configClass.getDeclaredAnnotation(ComponentScan.class);
   //2. 通过ComponentScan的value =》即要扫描的包
   String path = componentScan.value();

   //得到要扫描包下的所有资源(.class)
   //1) 得到类的加载器
   ClassLoader classLoader = JlSpringApplicationContext.class.getClassLoader();
   //2) 通过类的加载器获取到要扫描的包的资源url
   path = path.replace(".","/");
   URL resource = classLoader.getResource(path);
   //3) 将要加载的资源(.class)路径下的文件进行遍历=》io
   File file = new File(resource.getFile());
   if (file.isDirectory()){
       File[] files = file.listFiles();
       for (File f : files) {
           //class文件的绝对路径
           String fileAbsolutePath = f.getAbsolutePath();
           // 这里我们进行过滤,只处理.class文件
           if (fileAbsolutePath.endsWith(".class")) {
               //1. 获取到类名
               String className = fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
               //2. 获取类的全路径
               String classFullName = path.replace("/", ".") + "." + className;
               //3. 判断该.class文件是不是需要注入到容器中;看该类是不是有注解@Component @Service
               try {
                   //这是我们就得到了该类的Class对象
                   // 这里也可以通过class.forName得到一个Class对象
                   // 区别是:class.forName()会调用类的静态方法,classLoader.loadClass()不会
                   Class<?> clazz = classLoader.loadClass(classFullName);
                   //aClass.isAnnotationPresent(Component.class) 判断该类是否有@Component注解
                   if (clazz.isAnnotationPresent(Component.class)){
                       System.out.println("这是一个SpringBean=" + clazz + " 类名=" + className);

                       // 为了方便,我们将后置处理器放入集合中(真实的还是在走createBean和getBean这些逻辑,这里是简化的)
                       // 如果是一个后置处理器就放入集合中
                       // 这里我们不能通过instanceof来判断是否实现了BeanPostProcessor
                       // 原因:这个的clazz是一个类对象,不是一个实例对象
                       if (BeanPostProcessor.class.isAssignableFrom(clazz)){
                           BeanPostProcessor beanPostProcessor = (BeanPostProcessor)clazz.newInstance();
                           beanPostProcessorList.add(beanPostProcessor);
                           continue;
                       }
                       //先得到beanName
                       // 1. 得到component注解
                       Component declaredAnnotation = clazz.getDeclaredAnnotation(Component.class);
                       // 2. 得到value值(1.配置了value 2.没有配置value)
                       String beanName = declaredAnnotation.value();
                       if ("".equals(beanName)){ // 如果没有写value
                           // 将该类的类名首字母小写作为beanName
                           beanName = StringUtils.uncapitalize(className);
                       }
                       // 3. 将bean的信息封装到BeanDefinition对象
                       BeanDefinition beanDefinition = new BeanDefinition();
                       beanDefinition.setClazz(clazz);
                       // 4. 获取scope的值
                       if(clazz.isAnnotationPresent(Scope.class)){// 如果有scope值
                           Scope scopeAnnotation = clazz.getDeclaredAnnotation(Scope.class);
                           beanDefinition.setScope(scopeAnnotation.value());
                       }else { //如果没有scope值
                           beanDefinition.setScope("singleton");
                       }
                       // 5. 将BeanDefinition放入到Map中
                       beanDefinitionMap.put(beanName,beanDefinition);
                   }else {
                       System.out.println("这不是一个SpringBean=" + clazz + " 类名" + className);
                   }
               } catch (Exception e) {
                   e.printStackTrace();
               }

           }
       }
   }
}
  1. 因为我们需要知道需要扫描的包的路径,所以需要借助配置类。我们这里将配置类的Class对象作为参数传递给我们的容器类的构造器(这一步在容器的构造器中体现)。
  2. 有了配置类的Class对象之后,我们就可以通过@ComponentScan拿到要扫描类的路径。
  3. 拿到包的路径之后,就得去扫描包中的类,而且得判断哪些类是加了@Component。只有加了此注解的将来才可以注入到容器中。
  4. 如果有@Component,那么还得判断它是否是后置处理器,如何是后置处理器,实例化之后就将其直接加入到后置处理器集合中。
  5. 如果不是后置处理器,接下来拿到@Component中的value值。如果没有value值为空,就默认按照id=类名首字母小写的方式命名。如果value值不为空,就将获取到的value值作为id。
  6. 接下来判断,类上是否有@Scope。如果有就拿到它的value值,反之就默认为singleton(单例)。最后将此信息存入到BeanDefinition中。BeanDefinition结构:
package com.jl.spring.ioc;
/**
 * 用于记录bean的信息(bean为单例还是多例Scope;bean对应的class对象,反射可以生成对应的对象)
 *
 */
public class BeanDefinition {
    private String scope;
    private Class clazz;

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

    public BeanDefinition() {
    }

    @Override
    public String toString() {
        return "BeanDefinition{" +
                "scope='" + scope + '\'' +
                ", clazz=" + clazz +
                '}';
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }

    public Class getClazz() {
        return clazz;
    }

    public void setClazz(Class clazz) {
        this.clazz = clazz;
    }
}
  1. 之后将我们得到的beanName(也就是id值)beanDefinition(记录单例还是多例),存到我们的beanDefinitionMap

完成Bean实例的创建

在上一步中我们对所有的类进行了扫描,并且将所有Bean的信息存入到了beanDefinitionMap中。接下来我们就可以创建Bean实例了。

// 完成  createBean(BeanDefinition beanDefinition)方法
private Object createBean(String beanName,BeanDefinition beanDefinition){
    // 得到bean的class对象
    Class clazz = beanDefinition.getClazz();
    // 使用反射得到实例
    try {
        Object instance = clazz.getDeclaredConstructor().newInstance();
        // 注入对象
        // 1. 遍历当前要创建的对象的所有字段
        for (Field declaredField : clazz.getDeclaredFields()){
            //2.  判断该字段是否有Autowired修饰
            if (declaredField.isAnnotationPresent(Autowired.class)){
                // 3.得到字段的名称
                String name = declaredField.getName();
                // 4.通过getBean方法来获取要组装对象
                Object bean = getBean(name);
                // 5. 进行组装
                // 因为属性是私有的,所以要暴破
                declaredField.setAccessible(true);
                declaredField.set(instance,bean);
            }

        }
        System.out.println("创建好了一个实例" + instance);


        // 我们在Bean的初始化方法前,调用我们后置处理器的before方法
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
            // 在后置处理器的before方法,可以对容器生成的bean进行处理
            // 然后返回处理后的bean实例
            Object current = beanPostProcessor.postProcessBeforeInitialization(instance,beanName);
            if (current != null){
                instance = current;
            }
        }

        //判断是否需要执行Bean的初始化方法
        // 1. 判断当前创建的Bean对象是否实现了InitializingBean
        if (instance instanceof InitializingBean){ //如果实现了InitializingBean
            // 将 instance转成接口类型
            try {
                ((InitializingBean)instance).afterPropertiesSet();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // 我们在Bean的初始化方法前,调用我们后置处理器的after方法
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
            // 在后置处理器的after方法,可以对容器生成的bean进行处理
            // 然后返回处理后的bean实例
            Object current = beanPostProcessor.postProcessAfterInitialization(instance,beanName);
            if (current != null){
                instance = current; 
            }
        }
        System.out.println("-----------------------------------------");
        return instance;
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }
    // 如果反射对象失败,则返回空
    return null;
}
  1. 我们从BeanDefinition中拿到需要创建的Class对象。
  2. 使用Class对象通过反射来创建Bean对象实例。
  3. 因为我们创建对象中还有属性,所以还得考虑自动装配的情况。
  4. 拿到所有Class对象所有的Field对象数组,遍历判断是否有@Autowired。如果有就拿到此属性的名称,以此名称作为id去获取容器中的创建好的Bean实例。最后通过反射完成对属性的赋值。这里还得对属性进行暴破,因为属性是私有的.
  5. 接下来还不能将Bean注入到容器中,因为我们还有后置处理器初始化类
  6. BeanPostProcessor结构:
package com.jl.spring.processor;

import org.apache.commons.lang.StringUtils;

/**
 * 参考原生Spring容器定义的一个接口
 * 该接口有两个方法
 */
public interface BeanPostProcessor {
    /**
     * 这连个方法会对所有的bean生效
     * 该方法在bean的初始化方法前调用
     * @param bean
     * @param beanName
     * @return
     */
    default Object postProcessBeforeInitialization(Object bean, String beanName){
        return bean;
    };

    /**
     *  该方法在bena的初始化方法之后调用
     * @param bean
     * @param beanName
     * @return
     */
    default Object postProcessAfterInitialization(Object bean, String beanName){
        return bean;
    };
}
  1. 遍历我们的beanPostProcessorList(后置处理器集合),调用它们的postProcessBeforeInitialization(),实现对Bean实例的前置处理。
  2. 判断当前的Bean对象是否实现了InitializingBean。如果实现了,执行它的afterPropertiesSet()InitializingBean结构如下:
package com.jl.spring.processor;

/**
 * 根据原生Spring定义一个接口
 * 这个接口有一个方法
 * afterPropertiesSet在Bean的Setter方法后执行,即就是我们的初始化方法
 * 当一个Bean实现这个接口后,就实现afterPropertiesSet
 */
public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}
  1. 遍历我们的beanPostProcessorList(后置处理器集合),调用它们的postProcessAfterInitialization(),实现对Bean实例的后置处理。
  2. 最后返回我们的创建好的Bean实例。

获取Bean实例

// 编写方法返回容器的对象
public Object getBean(String name){
    // 判断传入的beanName是否在beanDefinition中存在
    if (beanDefinitionMap.containsKey(name)){
        BeanDefinition beanDefinition = beanDefinitionMap.get(name);
        // 得到beanDefinition的scope,分别进行处理
        if("singleton".equalsIgnoreCase(beanDefinition.getScope())){
            // 单例的,直接从单例池中获取
            return  singletonObjects.get(name);
        }else { // 如果不是单例,就通过createBean,反射一个对象
            return createBean(name,beanDefinition);
        }
    }else {
        // 如果不存在
        throw new NullPointerException("没有该bean");
    }
}
  1. 获取Bean实例,首先就得判断容器中是否有该Bean的信息。
  2. 判断要获取的Bean是否是单例,如果是单例就直接从单例池singletonObjects中获取。如果不是就调用createBean(),造一个Bean实例返回。

容器的构造方法

public JlSpringApplicationContext(Class configClass){
    beanDefinitionByScan(configClass);
    // 通过beanDefinition对象,初始化singletonObject单例池
    Enumeration<String> keys = beanDefinitionMap.keys();
    // 遍历所有的beanDefinition对象
    while (keys.hasMoreElements()){
        String beanName = keys.nextElement();
        // 通过beanName得到对应的beanDefinition对象
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        // 判断该bean是singleton还是一个prototype
        if ("singleton".equalsIgnoreCase(beanDefinition.getScope())){
            // 将该bean实例放入到singletonObjects这个集合中
            Object bean = createBean(beanName,beanDefinition);
            singletonObjects.put(beanName,bean);
        }
    }
//        System.out.println("单例池" + singletonObjects);
}

测试

Bean的测试(默认)

配置类

package com.jl.spring.ioc;

import com.jl.spring.annotation.ComponentScan;

/**
 * 这是一个配置类,作用类似我们原生spring的beans.xml 容器配置文件
 */
@ComponentScan(value = "com.jl.spring.component")
public class JlSpringConfig {
}

测试类:

package com.jl.spring;

import com.jl.spring.component.MonsterService;
import com.jl.spring.component.SmartAnimalable;
import com.jl.spring.ioc.JlSpringApplicationContext;
import com.jl.spring.ioc.JlSpringConfig;

public class AppMain {
    public static void main(String[] args) {
        JlSpringApplicationContext jlSpringApplicationContext =
                new JlSpringApplicationContext(JlSpringConfig.class);
        Object car = jlSpringApplicationContext.getBean("car");
        System.out.println(car);
    }
}

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

Bean的测试(通过指定id)

package com.jl.spring.component;

import com.jl.spring.annotation.Component;

@Component(value = "myCar")
public class Car {
}

测试类:

package com.jl.spring;

import com.jl.spring.component.MonsterService;
import com.jl.spring.component.SmartAnimalable;
import com.jl.spring.ioc.JlSpringApplicationContext;
import com.jl.spring.ioc.JlSpringConfig;

public class AppMain {
    public static void main(String[] args) {
        JlSpringApplicationContext jlSpringApplicationContext =
                new JlSpringApplicationContext(JlSpringConfig.class);
        Object car = jlSpringApplicationContext.getBean("myCar");
        System.out.println(car);
    }
}

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

自动装配测试

package com.jl.spring.component;

import com.jl.spring.annotation.Component;
import com.jl.spring.processor.InitializingBean;

@Component(value = "monsterDao")
public class MonsterDao implements InitializingBean {
    public void hi(){
        System.out.println("MonsterDao-hi()被调用。。。");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("MonsterDao初始化方法被调用");
    }
}
package com.jl.spring.component;

import com.jl.spring.annotation.Autowired;
import com.jl.spring.annotation.Component;
import com.jl.spring.annotation.Scope;
import com.jl.spring.processor.InitializingBean;

/**
 * MonsterService是一个service
 */
@Component(value = "monsterService") // 把MonsterService注入到我们自己的Spring容器中
public class MonsterService implements InitializingBean {
    @Autowired
    private MonsterDao monsterDao;
    public void m1(){
        monsterDao.hi();
    }

    /**
     * 该方法就是Bean的方法执行过后,被容器调用
     * 即就是初始化方法
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("MonsterService初始化方法被调用");
    }
}

测试类:

package com.jl.spring;

import com.jl.spring.component.MonsterService;
import com.jl.spring.component.SmartAnimalable;
import com.jl.spring.ioc.JlSpringApplicationContext;
import com.jl.spring.ioc.JlSpringConfig;

public class AppMain {
    public static void main(String[] args) {
        JlSpringApplicationContext jlSpringApplicationContext =
                new JlSpringApplicationContext(JlSpringConfig.class);
        Object bean = jlSpringApplicationContext.getBean("monsterService");
        System.out.println(bean);
    }
}

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

单例多例测试

package com.jl.spring.component;

import com.jl.spring.annotation.Autowired;
import com.jl.spring.annotation.Component;
import com.jl.spring.annotation.Scope;
import com.jl.spring.processor.InitializingBean;

/**
 * MonsterService是一个service
 */
@Component(value = "monsterService") // 把MonsterService注入到我们自己的Spring容器中
@Scope(value = "prototype")
public class MonsterService implements InitializingBean {
    @Autowired
    private MonsterDao monsterDao;
    public void m1(){
        monsterDao.hi();
    }

    /**
     * 该方法就是Bean的方法执行过后,被容器调用
     * 即就是初始化方法
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("MonsterService初始化方法被调用");
    }
}

测试类

package com.jl.spring;

import com.jl.spring.component.MonsterService;
import com.jl.spring.component.SmartAnimalable;
import com.jl.spring.ioc.JlSpringApplicationContext;
import com.jl.spring.ioc.JlSpringConfig;

public class AppMain {
    public static void main(String[] args) {
        JlSpringApplicationContext jlSpringApplicationContext =
                new JlSpringApplicationContext(JlSpringConfig.class);
        Object bean = jlSpringApplicationContext.getBean("monsterService");
        Object bean1 = jlSpringApplicationContext.getBean("monsterService");
        System.out.println(bean);
        System.out.println(bean1);
    }
}

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

后置处理器和初始化方法的测试

package com.jl.spring.component;

import com.jl.spring.annotation.Component;
import com.jl.spring.processor.InitializingBean;

@Component(value = "myCar")
public class Car implements InitializingBean {
    public Car() {
        System.out.println("Car无参构造被调用...");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("初始化方法");
    }
}
package com.jl.spring.component;

import com.jl.spring.annotation.Component;
import com.jl.spring.processor.BeanPostProcessor;

@Component
public class BeanPostProcessorImpl implements BeanPostProcessor{
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("前置通知");
        return null;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("后置通知");
        return null;
    }
}

测试类:

package com.jl.spring;

import com.jl.spring.component.MonsterService;
import com.jl.spring.component.SmartAnimalable;
import com.jl.spring.ioc.JlSpringApplicationContext;
import com.jl.spring.ioc.JlSpringConfig;

public class AppMain {
    public static void main(String[] args) {
        JlSpringApplicationContext jlSpringApplicationContext =
                new JlSpringApplicationContext(JlSpringConfig.class);
        Object car = jlSpringApplicationContext.getBean("myCar");
        System.out.println(car);
    }
}

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

AOP的编写

我们AOP和后置处理器有所联系。AOP就是利用前后置处理器进行切面处理。单例加强。

我们先看一下,用后置处理器实现的切面。

package com.jl.spring.component;

public interface SmartAnimalable {
    float getSum(float i ,float j);
    float getSub(float i ,float j);
}
package com.jl.spring.component;

import com.jl.spring.annotation.Component;

@Component(value="smartDog")
public class SmartDog implements SmartAnimalable{
    @Override
    public float getSum(float i, float j) {
        float res = i+j;
        System.out.println("SmartDog-getSum-res=" + res);
        return res;
    }


    @Override
    public float getSub(float i, float j) {
        float res = i -j;
        System.out.println("SmartDog-getSub-res=" + res);
        return res;
    }
}

后置处理器实现类:

package com.jl.spring.component;

import com.jl.spring.annotation.Component;
import com.jl.spring.processor.BeanPostProcessor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 这是我们自己的后置处理器
 * 它是实现了BeanPostProcessor
 * 我们可以重写里边的方法
 * 在Spring容器中仍然将我们的后置处理器当作一个Bean来处理,要注入到容器中
 * 还得考虑多个后置处理器的情况
 */
@Component
public class JlBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("后置处理器的JlBeanPostProcessor的before()方法被调用" + bean.getClass() + " beanName=" + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("后置处理器的JlBeanPostProcessor的after()方法被调用" + bean.getClass() + " beanName=" + beanName);
        // 实现AOP,返回代理对象,即对Bean进行包装
        if("smartDog".equals(beanName)){
            // 使用JDK的动态代理,返回Bean的代理对象
            Object proxyInstance = Proxy.newProxyInstance(JlBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(),
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            System.out.println("method"+ method.getName());
                            Object result = null;
                            // 加入要进行前置通知处理的方法是getSum
                            if ("getSum".equals(method.getName())){
                                SmartAnimalAspect.showBeginLog();
                                result = method.invoke(bean,args);
                                // 进行返回通知的处理
                                SmartAnimalAspect.showSuccessLog();
                            }else {
                                result = method.invoke(bean,args);
                            }
                            return result;
                        }
                    });
            // 如果bean是需要返回代理对象的,这里就直接返回代理对象
            return proxyInstance;
        }
        // 如果不需要AOP处理,我们就返回原生对象
        return bean;
    }
}

看到这里不知道小伙伴们有种似曾相识的感juo。没错!这里就是我们【AOP引入篇】中提到的动态代理。我们因为是简单演示,所以这里只是在postProcessAfterInitialization()中做了处理。

测试类:

package com.jl.spring;

import com.jl.spring.component.MonsterService;
import com.jl.spring.component.SmartAnimalable;
import com.jl.spring.ioc.JlSpringApplicationContext;
import com.jl.spring.ioc.JlSpringConfig;

public class AppMain {
    public static void main(String[] args) {
        JlSpringApplicationContext jlSpringApplicationContext =
                new JlSpringApplicationContext(JlSpringConfig.class);
 // 测试AOP是否生效
        SmartAnimalable smartDog = (SmartAnimalable)jlSpringApplicationContext.getBean("smartDog");
        smartDog.getSum(10,2);
        smartDog.getSub(10,2);
        System.out.println(smartDog.getClass());
    }
}

结果截图:
在这里插入图片描述
我们只对getSum做了增强,所以结果显示也只是对getSum的增强。
其实真正的AOP也和这个很类似,但他对很多内容进行了封装。我们下边模拟一个AOP:

package com.jl.spring.component;

public interface SmartAnimalable {
    float getSum(float i ,float j);
    float getSub(float i ,float j);
}

切面类

package com.jl.spring.component;

import com.jl.spring.annotation.*;

/**
 * 先将SmartAnimalAspect当作一个切面类来使用
 * 后面再改的更加灵活
 */
@Aspect
@Component
public class SmartAnimalAspect {
    @Before(value = "execution float com.jl.spring.component.SmartDog.getSum")
    public static void showBeginLog(){
        System.out.println("前置通知");
    }
    @AfterReturning(value = "execution float com.jl.spring.component.SmartDog.getSum")
    public static void showSuccessLog(){
        System.out.println("返回通知");
    }
}
package com.jl.spring.component;

import com.jl.spring.annotation.Component;

@Component(value="smartDog")
public class SmartDog implements SmartAnimalable{
    @Override
    public float getSum(float i, float j) {
        float res = i+j;
        System.out.println("SmartDog-getSum-res=" + res);
        return res;
    }


    @Override
    public float getSub(float i, float j) {
        float res = i -j;
        System.out.println("SmartDog-getSub-res=" + res);
        return res;
    }
}

测试类:
虽然是测试类,但这里边还对注解进行了处理,有兴趣的小伙伴可以将其抽取出来,做一些完善。

package com.jl.spring;

import com.jl.spring.annotation.AfterReturning;
import com.jl.spring.annotation.Before;
import com.jl.spring.component.SmartAnimalAspect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class JlTest {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        Class<SmartAnimalAspect> smartAnimalAspectClass = SmartAnimalAspect.class;
        for (Method declaredMethod : smartAnimalAspectClass.getDeclaredMethods()) {
            if(declaredMethod.isAnnotationPresent(Before.class)){

                String name = declaredMethod.getName();
                Before annotation = declaredMethod.getAnnotation(Before.class);
                String value = annotation.value();

                Method declaredMethod1 = smartAnimalAspectClass.getDeclaredMethod(declaredMethod.getName());
                declaredMethod1.invoke(smartAnimalAspectClass.newInstance(),null);
            }else if(declaredMethod.isAnnotationPresent(AfterReturning.class)){
                String name = declaredMethod.getName();
                Before annotation = declaredMethod.getAnnotation(Before.class);
                String value = annotation.value();

                Method declaredMethod1 = smartAnimalAspectClass.getDeclaredMethod(declaredMethod.getName());
                declaredMethod1.invoke(smartAnimalAspectClass.newInstance(),null);
            }
        }
    }
}

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

总结

以上就是我们手写的一个简易的Spring,主要是帮助大家理解Spring的基本执行流程。

如果文章中有描述不准确或者错误的地方,还望指正。您可以留言📫或者私信我。🙏
最后希望大家多多 关注+点赞+收藏^_^,你们的鼓励是我不断前进的动力!!!
感谢感谢~~~🙏🙏🙏

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艺术留白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值