【Spring(七)】带你手写一个Spring容器
创始人
2024-03-06 17:22:40

有关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 beanDefinitionMap = new ConcurrentHashMap<>();
// 定义属性SingletonObjects->存放单例对象
private ConcurrentHashMap singletonObjects= new ConcurrentHashMap<>();
// 定义属性,存放我们的后置处理器
private List 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) 通过类的加载器获取到要扫描的包的资源urlpath = path.replace(".","/");URL resource = classLoader.getResource(path);//3) 将要加载的资源(.class)路径下的文件进行遍历=》ioFile 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 @Servicetry {//这是我们就得到了该类的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// 将该类的类名首字母小写作为beanNamebeanName = 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() {}@Overridepublic 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对象是否实现了InitializingBeanif (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 keys = beanDefinitionMap.keys();// 遍历所有的beanDefinition对象while (keys.hasMoreElements()){String beanName = keys.nextElement();// 通过beanName得到对应的beanDefinition对象BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);// 判断该bean是singleton还是一个prototypeif ("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()被调用。。。");}@Overridepublic 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 {@Autowiredprivate MonsterDao monsterDao;public void m1(){monsterDao.hi();}/*** 该方法就是Bean的方法执行过后,被容器调用* 即就是初始化方法* @throws Exception*/@Overridepublic 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 {@Autowiredprivate MonsterDao monsterDao;public void m1(){monsterDao.hi();}/*** 该方法就是Bean的方法执行过后,被容器调用* 即就是初始化方法* @throws Exception*/@Overridepublic 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无参构造被调用...");}@Overridepublic 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{@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) {System.out.println("前置通知");return null;}@Overridepublic 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{@Overridepublic float getSum(float i, float j) {float res = i+j;System.out.println("SmartDog-getSum-res=" + res);return res;}@Overridepublic 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 {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) {System.out.println("后置处理器的JlBeanPostProcessor的before()方法被调用" + bean.getClass() + " beanName=" + beanName);return bean;}@Overridepublic 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() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("method"+ method.getName());Object result = null;// 加入要进行前置通知处理的方法是getSumif ("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{@Overridepublic float getSum(float i, float j) {float res = i+j;System.out.println("SmartDog-getSum-res=" + res);return res;}@Overridepublic 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 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的基本执行流程。

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

相关内容

热门资讯

猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...