手写Spring底层机制的实现【初始化IOC容器+依赖注入+BeanPostProcesson机制+AOP】

发布于:2025-09-13 ⋅ 阅读:(17) ⋅ 点赞:(0)

摘要:建议先看“JAVA----Spring的AOP和动态代理”这个文章,解释都在代码中!

一:提出问题依赖注入

1.单例

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:comtext="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!--   1. 如果我们是普通的java项目, beans.xml 放在src下
    2. 如果我们是java maven 项目, beans.xml 放在 src/main/resources  -->
    <comtext:component-scan base-package="com.campus.spring.component"/>
</beans>

UserAction

package com.campus.spring.component;

import org.springframework.stereotype.Component;

@Component
public class UserAction {
}

UserDao

package com.campus.spring.component;

import org.springframework.stereotype.Component;

//可以使用 @Repository
@Component
public class UserDao {
    public void hi(){
        System.out.println("hi。。。。。。。。。。。。。。");
    }
}

UserService

package com.campus.spring.component;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

// 可以使用@Service
@Component
public class UserService {
    @Autowired
    private UserDao userDao;
    public void m1(){
        userDao.hi();
    }
}

package com.campus.spring;

import com.campus.spring.component.UserAction;
import com.campus.spring.component.UserDao;
import com.campus.spring.component.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppMain {
    public static void main(String[] args) {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        UserAction userAction =(UserAction) ioc.getBean("userAction");
        UserAction userAction2 =(UserAction) ioc.getBean("userAction");
        System.out.println("userAction="+ userAction);
        System.out.println("userAction2="+ userAction2);

        UserDao userDao = (UserDao) ioc.getBean("userDao");
        System.out.println("userDao="+ userDao);

        UserService userService = (UserService) ioc.getBean("userService");
        System.out.println("userService="+ userService);
    }
}

运行结果:

userAction=com.campus.spring.component.UserAction@54d9d12d
userAction2=com.campus.spring.component.UserAction@54d9d12d
userDao=com.campus.spring.component.UserDao@38425407
userService=com.campus.spring.component.UserService@43bc63a3
注:userAction和userAction2的结果一样;
如果我们是普通的java项目, beans.xml 放在src下;
如果我们是java maven 项目, beans.xml 放在 src/main/resources ;

2.多例

UserAction

package com.campus.spring.component;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Scope(value = "prototype")
@Component
public class UserAction {
}

其他代码一样

运行结果
userAction=com.campus.spring.component.UserAction@dd05255
userAction2=com.campus.spring.component.UserAction@6a78afa0
userDao=com.campus.spring.component.UserDao@2f4948e4
userService=com.campus.spring.component.UserService@1f2586d6
注:在默认情况下 我们配置@Component @Controller @Service @Repository 是单例 @Scope(value = "prototype") 表示以多实例形式,返回UserAction bean

问题一:加入 @Autowired ,Spring容器时如何实现依赖注入 和  (单例和多列)怎么实现的?

二:提出问题BeanPostProcessor

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:comtext="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <comtext:component-scan base-package="com.campus.spring.component"/>

    <!--配置后置处理器-->
    <bean class="com.campus.spring.process.MyBeanPostProcessor" id="myBeanPostProcessor"/>
</beans>

UserAction

package com.campus.spring.component;

import org.springframework.stereotype.Component;

@Component
public class UserAction {
}

UserDao

package com.campus.spring.component;

import org.springframework.stereotype.Component;

//可以使用 @Repository
@Component
public class UserDao {
    public void hi(){
        System.out.println("hi。。。。。。。。。。。。。。");
    }
}

UserService

package com.campus.spring.component;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


//也可以使用@Service
@Component
public class UserService {
    //定义属性
    //思考:加入 @Autowired , Spring容器时如何实现依赖注入?
    //也可以使用@Resource
    @Autowired
    private UserDao userDao;

    public void m1() {
        userDao.hi();
    }

    //这里我们需要指定init() 是初始化方法
    @PostConstruct
    public void init() {
        System.out.println("UserService-init()");
    }

}

AppMain

package com.campus.spring;

import com.campus.spring.component.UserAction;
import com.campus.spring.component.UserDao;
import com.campus.spring.component.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppMain {
    public static void main(String[] args) {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        UserAction userAction =(UserAction) ioc.getBean("userAction");
        UserAction userAction2 =(UserAction) ioc.getBean("userAction");
        System.out.println("userAction="+ userAction);
        System.out.println("userAction2="+ userAction2);

        UserDao userDao = (UserDao) ioc.getBean("userDao");
        System.out.println("userDao="+ userDao);

        UserService userService = (UserService) ioc.getBean("userService");
        System.out.println("userService="+ userService);
    }
}

MyBeanPostProcessor(后置处理器)

package com.campus.spring.process;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * 编写的一个后置处理器
 */
//@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    /**
     * 在Bean的 init初始化方法前调用
     * @param bean 就是ioc 容器返回的bean 对象, 如果这里被替换会修改,则返回的bean 对象也会被修改
     * @param beanName 就是ioc 容器配置的bean 的名称
     * @return  beanName 就是返回的bean 对象
     * @throws BeansException
     */
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        System.out.println("postProcessBeforeInitialization 被 调 用 " + beanName + " bean= " + bean.getClass());
        return bean;
    }

    /**
*	在Bean的 init初始化方法后调用
*	@param bean : 就是ioc 容器返回的bean 对象, 如果这里被替换会修改,则返回的bean 对象也会被修改
*	@param beanName: 就是ioc 容器配置的bean 的名称
*	@return Object: 就是返回的bean 对象
*/

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization 被 调 用 " + beanName + " bean= " + bean.getClass());
        return bean;
    }
}

运行结果(后置处理器有4组):

postProcessBeforeInitialization 被 调 用 userDao bean= class com.campus.spring.component.UserDao
postProcessAfterInitialization 被 调 用 userDao bean= class com.campus.spring.component.UserDao
postProcessBeforeInitialization 被 调 用 userService bean= class com.campus.spring.component.UserService
UserService-init()
postProcessAfterInitialization 被 调 用 userService bean= class com.campus.spring.component.UserService
postProcessBeforeInitialization 被 调 用 userAction bean= class com.campus.spring.component.UserAction
postProcessAfterInitialization 被 调 用 userAction bean= class com.campus.spring.component.UserAction
postProcessBeforeInitialization 被 调 用 userAction bean= class com.campus.spring.component.UserAction
postProcessAfterInitialization 被 调 用 userAction bean= class com.campus.spring.component.UserAction
userAction=com.campus.spring.component.UserAction@2362f559
userAction2=com.campus.spring.component.UserAction@b2c9a9c
userDao=com.campus.spring.component.UserDao@4c178a76
userService=com.campus.spring.component.UserService@fa4c865

注:如果把UserAction.java中的@Scope(value = "prototype") 去掉,则后置处理器有3组;

运行结果:
postProcessBeforeInitialization 被 调 用 userAction bean= class com.campus.spring.component.UserAction
postProcessAfterInitialization 被 调 用 userAction bean= class com.campus.spring.component.UserAction
postProcessBeforeInitialization 被 调 用 userDao bean= class com.campus.spring.component.UserDao
postProcessAfterInitialization 被 调 用 userDao bean= class com.campus.spring.component.UserDao
postProcessBeforeInitialization 被 调 用 userService bean= class com.campus.spring.component.UserService
UserService-init()
postProcessAfterInitialization 被 调 用 userService bean= class com.campus.spring.component.UserService
userAction=com.campus.spring.component.UserAction@3d285d7e
userAction2=com.campus.spring.component.UserAction@3d285d7e
userDao=com.campus.spring.component.UserDao@40005471
userService=com.campus.spring.component.UserService@2cd76f31

问题二:原生 Spring容器实现  BeanPostProcessor ?

三:问题三

beans.xml

AppMain

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:comtext="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--   1. 如果我们是普通的java项目, beans.xml 放在src下
    2. 如果我们是java maven 项目, beans.xml 放在 src/main/resources  -->
    <comtext:component-scan base-package="com.campus.spring.component"/>
    <comtext:component-scan base-package="com.campus.spring.aop"/>

    <!--配置后置处理器-->
    <bean class="com.campus.spring.process.MyBeanPostProcessor" id="myBeanPostProcessor"/>


    <!--启用基于注解方式的AOP功能-->
    <aop:aspectj-autoproxy/>
</beans>

SmartAnimalable接口

package com.campus.spring.aop;

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

SmartAnimalAspect

package com.campus.spring.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * 这是一个切面类
 */
@Component
@Aspect
public class SmartAnimalAspect {

    //给SmartDog配置前置,返回,异常,最终通知

    //前置通知
    @Before(value = "execution(public float com.campus.spring.aop.SmartDog.getSum(float, float))")
    public void showBeginLog(JoinPoint joinPoint) {
        //通过连接点对象joinPoint 可以获取方法签名
        Signature signature = joinPoint.getSignature();
        System.out.println("SmartAnimalAspect-切面类showBeginLog()[使用的myPointCut()]-方法执行前-日志-方法名-" + signature.getName() + "-参数 "
                + Arrays.asList(joinPoint.getArgs()));
    }

   //返回通知
    @AfterReturning(value = "execution(public float com.campus.spring.aop.SmartDog.getSum(float, float))", returning = "res")
    public void showSuccessEndLog(JoinPoint joinPoint, Object res) {
        Signature signature = joinPoint.getSignature();
        System.out.println("SmartAnimalAspect-切面类showSuccessEndLog()-方法执行正常结束-日志-方法名-" + signature.getName() + " 返回的结果是=" + res);
    }


   //异常通知
    @AfterThrowing(value = "execution(public float com.campus.spring.aop.SmartDog.getSum(float, float))", throwing = "throwable")
    public void showExceptionLog(JoinPoint joinPoint, Throwable throwable) {
        Signature signature = joinPoint.getSignature();
        System.out.println("SmartAnimalAspect-切面类showExceptionLog()-方法执行异常-日志-方法名-" + signature.getName() + " 异常信息=" + throwable);
    }

    //最终通知
    @After(value = "execution(public float com.campus.spring.aop.SmartDog.getSum(float, float))")
    public void showFinallyEndLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        System.out.println("SmartAnimalAspect-切面类showFinallyEndLog()-方法最终执行完毕-日志-方法名-" + signature.getName());
    }

}

SmartDog

package com.campus.spring.aop;

import org.springframework.stereotype.Component;


@Component
public class SmartDog implements SmartAnimalable {

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

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

AppMain

package com.campus.spring;

import com.campus.spring.aop.SmartAnimalable;
import com.campus.spring.component.UserAction;
import com.campus.spring.component.UserDao;
import com.campus.spring.component.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppMain {
    public static void main(String[] args) {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        UserAction userAction =(UserAction) ioc.getBean("userAction");
        UserAction userAction2 =(UserAction) ioc.getBean("userAction");
        System.out.println("userAction="+ userAction);
        System.out.println("userAction2="+ userAction2);

        UserDao userDao = (UserDao) ioc.getBean("userDao");
        System.out.println("userDao="+ userDao);

        UserService userService = (UserService) ioc.getBean("userService");
        System.out.println("userService="+ userService);

        //测试 AOP
        SmartAnimalable smartDog = ioc.getBean(SmartAnimalable.class);
        smartDog.getSum(10, 2);

    }
}
运行结果:
postProcessBeforeInitialization 被 调 用 userDao bean= class com.campus.spring.component.UserDao
postProcessAfterInitialization 被 调 用 userDao bean= class com.campus.spring.component.UserDao
postProcessBeforeInitialization 被 调 用 userService bean= class com.campus.spring.component.UserService
UserService-init()
postProcessAfterInitialization 被 调 用 userService bean= class com.campus.spring.component.UserService
postProcessBeforeInitialization 被 调 用 smartAnimalAspect bean= class com.campus.spring.aop.SmartAnimalAspect
postProcessAfterInitialization 被 调 用 smartAnimalAspect bean= class com.campus.spring.aop.SmartAnimalAspect
postProcessBeforeInitialization 被 调 用 smartDog bean= class com.campus.spring.aop.SmartDog
postProcessAfterInitialization 被 调 用 smartDog bean= class jdk.proxy2.$Proxy20
postProcessBeforeInitialization 被 调 用 userAction bean= class com.campus.spring.component.UserAction
postProcessAfterInitialization 被 调 用 userAction bean= class com.campus.spring.component.UserAction
postProcessBeforeInitialization 被 调 用 userAction bean= class com.campus.spring.component.UserAction
postProcessAfterInitialization 被 调 用 userAction bean= class com.campus.spring.component.UserAction
userAction=com.campus.spring.component.UserAction@24c22fe
userAction2=com.campus.spring.component.UserAction@93081b6
userDao=com.campus.spring.component.UserDao@cd1e646
userService=com.campus.spring.component.UserService@7ba8c737
SmartAnimalAspect-切面类showBeginLog()[使用的myPointCut()]-方法执行前-日志-方法名-getSum-参数 [10.0, 2.0]
SmartDog-getSum-res=12.0
SmartAnimalAspect-切面类showSuccessEndLog()-方法执行正常结束-日志-方法名-getSum 返回的结果是=12.0
SmartAnimalAspect-切面类showFinallyEndLog()-方法最终执行完毕-日志-方法名-getSum

注:postProcessBeforeInitialization 被 调 用 smartDog bean= class com.campus.spring.aop.SmartDog
postProcessAfterInitialization 被 调 用 smartDog bean= class jdk.proxy2.$Proxy20

解释:当创建smartDog 对象/组件的时候,postProcessBeforeInitialization 的时候还是SmartDog,也就是初始化,但是postProcessAfterInitialization 后置处理器变成了代理对象,因为AOP返回的是代理对象

问题三:AOP 与 BeanPostProcessor 关系

简单分析AOP 与 BeanPostProcessor 关系

  1. AOP 实现 Spring 可以通过给一个类,加入注解 @EnableAspectJAutoProxy  来指定, 比如 

package com.campus.spring.aop;

import org.springframework.context.annotation.EnableAspectJAutoProxy;

@EnableAspectJAutoProxy
public class Test {
}
  1. 我们来追一下@EnableAspectJAutoProxy

  1. 看一下 AnnotationAwareAspectJAutoProxyCreator 的类图

  1. AOP 底层是基于 BeanPostProcessor 机制的.
  2. 即在 Bean 创建好后,根据是否需要 AOP 处理,决定返回代理对象,还是原生 Bean
  3. 在返回代理对象时,就可以根据要代理的类和方法来返回
  4. 其实这个机制并不难,本质就是在 BeanPostProcessor 机制 + 动态代理技术
  5. 下面我们就准备来实现 AOP 机制

四:Spring 整体架构分析

第一步:编写自己 Spring 容器,实现扫描包, 得到 bean 的 class 对象

1.分析示意图

知识扩展:类加载器
 java 的类加载器 3 种

1.Bootstrap 类加载器--------------对应路径 jre/lib
2.Ext 类加载器--------------------对应路径 jre/lib/ext
3.App 类加载器-------------------对应路径 classpath
● classpath 类路径,就是 java.exe 执行时,指定的路径,比如

 D:\program\hspjdk8\bin\java.exe                              "-javaagent:D:\program\JavaIDEA

2020.2\lib\idea_rt.jar=55992:D:\program\JavaIDEA      2020.2\bin"     -Dfile.encoding=UTF-8      -classpath D:\program\hspjdk8\jre\lib\charsets.jar;D:\program\hspjdk8\jre\lib\deploy.jar;D:\program\hspjdk8\jre\lib\ ext\access-bridge-64.jar;D:\program\hspjdk8\jre\lib\ext\cldrdata.jar;D:\program\hspjdk8\jre\lib\ext\dnsns. jar;D:\program\hspjdk8\jre\lib\ext\jaccess.jar;D:\program\hspjdk8\jre\lib\ext\jfxrt.jar;D:\program\hspjdk8 \jre\lib\ext\localedata.jar;D:\program\hspjdk8\jre\lib\ext\nashorn.jar;D:\program\hspjdk8\jre\lib\ext\sune

c.jar;D:\program\hspjdk8\jre\lib\ext\sunjce_provider.jar;D:\program\hspjdk8\jre\lib\ext\sunmscapi.jar;D:\ program\hspjdk8\jre\lib\ext\sunpkcs11.jar;D:\program\hspjdk8\jre\lib\ext\zipfs.jar;D:\program\hspjdk8\jr e\lib\javaws.jar;D:\program\hspjdk8\jre\lib\jce.jar;D:\program\hspjdk8\jre\lib\jfr.jar;D:\program\hspjdk8\jr e\lib\jfxswt.jar;D:\program\hspjdk8\jre\lib\jsse.jar;D:\program\hspjdk8\jre\lib\management-agent.jar;D:\p rogram\hspjdk8\jre\lib\plugin.jar;D:\program\hspjdk8\jre\lib\resources.jar;D:\program\hspjdk8\jre\lib\rt.j ar;D:\java_projects\hsp-myspring\target\classes com.hspedu.spring.AppMain

2.代码(解释在代码中)

com.campus.spring.annotation.Component(注释)
package com.campus.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 {
    String value() default ""; // 通过value 可以给注入的bean/对象指定名字
}
com.campus.spring.annotation.ComponentScan注释
package com.campus.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 ComponentScan {
    String value() default ""; // 表示可以传入一个 value 属性,指定要扫描的包
}
com.campus.spring.component.MonsterDao.java
package com.campus.spring.component;

import com.campus.spring.annotation.Component;

@Component(value = "monsterDao")
public class MonsterDao {

}
 com.campus.spring.component.MonsterService.java
package com.campus.spring.component;


import com.campus.spring.annotation.Component;

/**
 *	1. 使用@Component("monsterService") 修饰
 *	2. 给该MonsterService 注入到容器设置beanName 为 monsterService
 *	3. 如果没有设置,默认可以以类名首字母小写来玩
 */

@Component(value="monsterService")
public class MonsterService {
}
com.campus.spring.ioc.SpringApplicationContext.java
package com.campus.spring.ioc;

import com.campus.spring.annotation.Component;
import com.campus.spring.annotation.ComponentScan;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;

/*
SpringApplicationContext 类的作用类似于 Spring原生ioc容器
 */
public class SpringApplicationContext {
    private Class configClass;


    public SpringApplicationContext(Class configClass) {
        this.configClass = configClass;
        System.out.println(this.configClass);

        //获取要扫描的包
        //1.先得到 SpringConfig配置的@ComponentScan(value = "com.campus.spring.ComponentScan")
        ComponentScan componentScan = (ComponentScan)this.configClass.getDeclaredAnnotation(ComponentScan.class);
        System.out.println(componentScan);//@com.campus.spring.annotation.ComponentScan("com.campus.spring.component")
        //2.通过componentScan的value =》即要扫描的包
        String path = componentScan.value();
        System.out.println("要扫描的包= "+path);

        //得到要扫描的包下面的所有资源(类.class)
        //1.得到类的加载器
        ClassLoader classLoader = SpringApplicationContext.class.getClassLoader();

        //2.通过类的加载器获取要扫描的包的资源 url =》 类似于一个路径
        path = path.replace(".", "/");
        System.out.println("转换后的路径: " + path);
        URL resource = classLoader.getResource(path);

        System.out.println("resource= "+resource);
        //3.将要加载的资源(.class)路径下的文件进行遍历

        String decodedPath = null;
        try {
            decodedPath = URLDecoder.decode(resource.getFile(), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        File file = new File(decodedPath);
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {

                String fileAbsolutePath = f.getAbsolutePath();
                //这里我们只处理.class文件
                if (fileAbsolutePath.endsWith(".class")) {

                    //1. 获取到类名
                    String className =
                            fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
                    //System.out.println("className=" + className);
                    //2. 获取类的完整的路径(全类名)
                    //解读 path.replace("/",".") =》 com.campus.spring.component.
                    String classFullName = path.replace("/", ".") + "." + className;

                    //3. 判断该类是不是需要注入容器, 就看该类是不是有注解 @Component @Service..
                    try {
                        // aClass.isAnnotationPresent(Component.class) 判断该类是否有 @Component
                        Class<?> clazz = classLoader.loadClass(classFullName);
                        if (clazz.isAnnotationPresent(Component.class)) {

                                System.out.println("是一个Spring bean= "+clazz+" 类名= "+className);
                            }else {
                                System.out.println("不是一个Spring bean= "+clazz+" 类名= "+className);
                            }

                        }catch (Exception e) {
                        e.printStackTrace();
                    }
                    }
                }
            }
        }
    //编写方法返回对容器中对象
    public Object getBean(String name) {
        return null;
    }

    }


com.campus.spring.ioc.SpringConfig.java
package com.campus.spring.ioc;

/*
这是一个配置类,作用类似于我们原生的spring 的 beans.xml 容器配置文件
* */

import com.campus.spring.annotation.ComponentScan;

@ComponentScan(value = "com.campus.spring.component")
public class SpringConfig {
}
com.campus.spring.AppMain.java
package com.campus.spring;

import com.campus.spring.ioc.SpringApplicationContext;
import com.campus.spring.ioc.SpringConfig;



public class AppMain {
    public static void main(String[] args) throws ClassNotFoundException {
        //创建自己的容器
       SpringApplicationContext SpringApplicationContext = new SpringApplicationContext(SpringConfig.class);

    }
}
运行结果
class com.campus.spring.ioc.SpringConfig
componentScan= @com.campus.spring.annotation.ComponentScan("com.campus.spring.component")
要扫描的包= com.campus.spring.component
转换后的路径: com/campus/spring/component
resource= file:/E:/%e6%a1%86%e6%9e%b6%e6%8a%80%e6%9c%af%e5%ad%a6%e4%b9%a0/myspring/target/classes/com/campus/spring/component
是一个Spring bean= class com.campus.spring.component.MonsterService 类名= MonsterService
是一个Spring bean= class com.campus.spring.component.MonsterDao 类名= MonsterDao

第二步:扫描将 bean 信息封装到 BeanDefinition 对象, 并放入到 Map

分析:bean的作用域可能是singletion,也可能是prototype;所以需要一个注解来指定是singletion还是prototype

代码

pom.xml需要引入一个(为了“StringUtils”的使用,因为StringUtils.uncapitalize(className
)可以让className首字母大小写)
 <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
com.campus.spring.component.MonsterService(加了:“@Scope(value = "prototype")”)
package com.campus.spring.component;


import com.campus.spring.annotation.Component;
import com.campus.spring.annotation.Scope;

/**
 *	1. 使用@Component("monsterService") 修饰
 *	2. 给该MonsterService 注入到容器设置beanName 为 monsterService
 *	3. 如果没有设置,默认可以以类名首字母小写来玩(底层还有很多细节)
 */
@Scope(value = "prototype")
@Component(value="monsterService")
public class MonsterService {
}
com.campus.spring.ioc.SpringApplicationContext
package com.campus.spring.ioc;

import com.campus.spring.annotation.Component;
import com.campus.spring.annotation.ComponentScan;
import com.campus.spring.annotation.Scope;
import org.springframework.util.StringUtils;

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

/*
SpringApplicationContext 类的作用类似于 Spring原生ioc容器
 */
public class SpringApplicationContext {
    private Class configClass;


    //定义属性BeanDefinitionMap -> 存放BeanDefinition对象
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    //定义属性SingletonObjects -> 存放单例对象
    private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();



    public SpringApplicationContext(Class configClass) {
        this.configClass = configClass;
        System.out.println(this.configClass);

        //获取要扫描的包
        //1.先得到 SpringConfig配置的@ComponentScan(value = "com.campus.spring.ComponentScan")
        ComponentScan componentScan = (ComponentScan)this.configClass.getDeclaredAnnotation(ComponentScan.class);
        System.out.println("componentScan= "+componentScan);//@com.campus.spring.annotation.ComponentScan("com.campus.spring.component")
        //2.通过componentScan的value =》即要扫描的包
        String path = componentScan.value();
        System.out.println("要扫描的包= "+path);

        //得到要扫描的包下面的所有资源(类.class)
        //1.得到类的加载器
        ClassLoader classLoader = SpringApplicationContext.class.getClassLoader();

        //2.通过类的加载器获取要扫描的包的资源 url =》 类似于一个路径
        path = path.replace(".", "/");
        System.out.println("转换后的路径: " + path);
        URL resource = classLoader.getResource(path);

        System.out.println("resource= "+resource);
        //3.将要加载的资源(.class)路径下的文件进行遍历

        String decodedPath = null;
        try {
            decodedPath = URLDecoder.decode(resource.getFile(), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        File file = new File(decodedPath);
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {

                String fileAbsolutePath = f.getAbsolutePath();
                //这里我们只处理.class文件
                if (fileAbsolutePath.endsWith(".class")) {

                    //1. 获取到类名
                    String className =
                            fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
                    //System.out.println("className=" + className);
                    //2. 获取类的完整的路径(全类名)
                    //解读 path.replace("/",".") =》 com.campus.spring.component.
                    String classFullName = path.replace("/", ".") + "." + className;

                    //3. 判断该类是不是需要注入容器, 就看该类是不是有注解 @Component @Service..
                    try {
                        // aClass.isAnnotationPresent(Component.class) 判断该类是否有 @Component
                        Class<?> clazz = classLoader.loadClass(classFullName);
                        if (clazz.isAnnotationPresent(Component.class)) {
                                System.out.println("是一个Spring bean= "+clazz+" 类名= "+className);

                            //先得到beanName
                            //1. 得到Component注解
                            Component componentAnnotation =
                                    clazz.getDeclaredAnnotation(Component.class);
                            //2. 的配置value值
                            String beanName = componentAnnotation.value();
                            if ("".equals(beanName)) {//如果没有写value
                                //将该类的类名首字母小写作为beanName
                                beanName = StringUtils.uncapitalize(className);
                            }

                            //3.将Bean的信息封装到BeanDefinition对象->放入到BeanDefinitionMap
                            BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setClazz(clazz);
                            //4. 获取Scope值
                            if (clazz.isAnnotationPresent(Scope.class)) {
                                //如果配置了Scope, 获取他配置的值
                                Scope scopeAnnotation = clazz.getDeclaredAnnotation(Scope.class);//scopeAnnotation= @com.campus.spring.annotation.Scope("prototype")
                                //System.out.println("scopeAnnotation= "+scopeAnnotation);
                                beanDefinition.setScope(scopeAnnotation.value());//scopeAnnotation value = prototype
                               // System.out.println("scopeAnnotation value = "+scopeAnnotation.value());
                            } else {
                                //如果没有配置Scope, 就默认的值singleton
                                beanDefinition.setScope("singleton");
                            }

                            //蒋beanDefinition 对象放入到Map
                            beanDefinitionMap.put(beanName, beanDefinition);

                        }else {
                                System.out.println("不是一个Spring bean= "+clazz+" 类名= "+className);
                            }

                        }catch (Exception e) {
                        e.printStackTrace();
                    }
                    }
                }
            }
        }
    //编写方法返回对容器中对象
    public Object getBean(String name) {
        return null;
    }

    }


补充:isAnnotationPresent 方法是Java反射机制中的一个重要方法,它用于检查某个类、方法或字段是否存在指定类型的注解。如果存在,则返回 true;如果不存在,则返回 false;

getDeclaredAnnotation 方法用于获取直接修饰在元素(类、方法、构造函数、字段)上的指定注解。它不会获取继承的注解

其他代码不变
运行后:
com.campus.spring.ioc.SpringApplicationContext另外一个写法
package com.campus.spring.ioc;

import com.campus.spring.annotation.Component;
import com.campus.spring.annotation.ComponentScan;
import com.campus.spring.annotation.Scope;
import org.springframework.util.StringUtils;


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

/*
SpringApplicationContext 类的作用类似于 Spring原生ioc容器
 */
public class SpringApplicationContext {
    private Class configClass;


    //定义属性BeanDefinitionMap -> 存放BeanDefinition对象
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    //定义属性SingletonObjects -> 存放单例对象
    private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();



    public SpringApplicationContext(Class configClass) {
        setBeanDefinitionsScan(configClass);
        System.out.println("beanDefinitionMap= " + beanDefinitionMap);
        }


        public void setBeanDefinitionsScan(Class configClass){
            this.configClass = configClass;
            System.out.println(this.configClass);

            //获取要扫描的包
            //1.先得到 SpringConfig配置的@ComponentScan(value = "com.campus.spring.ComponentScan")
            ComponentScan componentScan = (ComponentScan)this.configClass.getDeclaredAnnotation(ComponentScan.class);
            System.out.println("componentScan= "+componentScan);//@com.campus.spring.annotation.ComponentScan("com.campus.spring.component")
            //2.通过componentScan的value =》即要扫描的包
            String path = componentScan.value();
            System.out.println("要扫描的包= "+path);

            //得到要扫描的包下面的所有资源(类.class)
            //1.得到类的加载器
            ClassLoader classLoader = SpringApplicationContext.class.getClassLoader();

            //2.通过类的加载器获取要扫描的包的资源 url =》 类似于一个路径
            path = path.replace(".", "/");
            System.out.println("转换后的路径: " + path);
            URL resource = classLoader.getResource(path);

            System.out.println("resource= "+resource);
            //3.将要加载的资源(.class)路径下的文件进行遍历

            String decodedPath = null;
            try {
                decodedPath = URLDecoder.decode(resource.getFile(), "UTF-8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
            File file = new File(decodedPath);
            if (file.isDirectory()) {
                File[] files = file.listFiles();
                for (File f : files) {

                    String fileAbsolutePath = f.getAbsolutePath();
                    //这里我们只处理.class文件
                    if (fileAbsolutePath.endsWith(".class")) {

                        //1. 获取到类名
                        String className =
                                fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
                        //System.out.println("className=" + className);
                        //2. 获取类的完整的路径(全类名)
                        //解读 path.replace("/",".") =》 com.campus.spring.component.
                        String classFullName = path.replace("/", ".") + "." + className;

                        //3. 判断该类是不是需要注入容器, 就看该类是不是有注解 @Component @Service..
                        try {
                            // aClass.isAnnotationPresent(Component.class) 判断该类是否有 @Component
                            Class<?> clazz = classLoader.loadClass(classFullName);
                            if (clazz.isAnnotationPresent(Component.class)) {
                                System.out.println("是一个Spring bean= "+clazz+" 类名= "+className);

                                //先得到beanName
                                //1. 得到Component注解
                                Component componentAnnotation =
                                        clazz.getDeclaredAnnotation(Component.class);
                                //2. 的配置value值
                                String beanName = componentAnnotation.value();
                                if ("".equals(beanName)) {//如果没有写value
                                    //将该类的类名首字母小写作为beanName
                                    beanName = StringUtils.uncapitalize(className);
                                }

                                //3.将Bean的信息封装到BeanDefinition对象->放入到BeanDefinitionMap
                                BeanDefinition beanDefinition = new BeanDefinition();
                                beanDefinition.setClazz(clazz);
                                //4. 获取Scope值
                                if (clazz.isAnnotationPresent(Scope.class)) {
                                    //如果配置了Scope, 获取他配置的值

                                    Scope scopeAnnotation = clazz.getDeclaredAnnotation(Scope.class);//scopeAnnotation= @com.campus.spring.annotation.Scope("prototype")
                                    //System.out.println("scopeAnnotation= "+scopeAnnotation);
                                    beanDefinition.setScope(scopeAnnotation.value());//scopeAnnotation value = prototype
                                    // System.out.println("scopeAnnotation value = "+scopeAnnotation.value());
                                } else {
                                    //如果没有配置Scope, 就默认的值singleton
                                    beanDefinition.setScope("singleton");
                                }

                                //蒋beanDefinition 对象放入到Map
                                beanDefinitionMap.put(beanName, beanDefinition);

                            }else {
                                System.out.println("不是一个Spring bean= "+clazz+" 类名= "+className);
                            }

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

    //编写方法返回对容器中对象
    public Object getBean(String name) {
        return null;
    }

    }


运行结果:
class com.campus.spring.ioc.SpringConfig
componentScan= @com.campus.spring.annotation.ComponentScan("com.campus.spring.component")
要扫描的包= com.campus.spring.component
转换后的路径: com/campus/spring/component
resource= file:/E:/%e6%a1%86%e6%9e%b6%e6%8a%80%e6%9c%af%e5%ad%a6%e4%b9%a0/myspring/target/classes/com/campus/spring/component
是一个Spring bean= class com.campus.spring.component.MonsterService 类名= MonsterService
是一个Spring bean= class com.campus.spring.component.MonsterDao 类名= MonsterDao
beanDefinitionMap= {monsterService=BeanDefinition{scope='prototype', clazz=class com.campus.spring.component.MonsterService}, monsterDao=BeanDefinition{scope='singleton', clazz=class com.campus.spring.component.MonsterDao}}
Hello World

第三部:初始化 bean 单例池,并完成 getBean 方法 , createBean 方法

3.1.初始化bean单例池 ,createBean 方法

3.1.1.代码

思路:

通过beanDefinitionMap ,

初始化singletonObjects 单例池

封装成方法

遍历所有的beanDefinition对象

//定义属性SingletonObjects -> 存放单例对象 
private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();   
private Object createBean(BeanDefinition beanDefinition) {
        //得到Bean的clazz对象
        Class clazz = beanDefinition.getClazz();
        try {
            //使用反射得到实例
            Object instance = clazz.getDeclaredConstructor().newInstance();
            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 SpringApplicationContext(Class configClass) {
        setBeanDefinitionsScan(configClass);


        //通过beanDefinitionMap , 初始化singletonObjects 单例池
        //封装成方法
        //遍历所有的beanDefinition对象
        //这里是java基础->集合和枚举
        Enumeration<String>keys=beanDefinitionMap.keys();
        while(keys.hasMoreElements()){
            //得到beanName
            String beanName = keys.nextElement();
            //通过beanName 得到对应的beanDefinition对象
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            //判断该bean是singleton还是prototype
            if ("singleton".equalsIgnoreCase(beanDefinition.getScope())) {
                //将该bean实例放入到singletonObjects 集合
                Object bean = createBean(beanDefinition);
                singletonObjects.put(beanName, bean);
            }
            System.out.println("==============================================");
            System.out.println("singletonObjects 单例池=" + singletonObjects);
            System.out.println("beanDefinitionMap=" + beanDefinitionMap);
            System.out.println("==============================================");
        }
        
    }
运行结果:

3.2.完成 getBean 方法(返回对容器中对象)

        //判断传入的beanName是否在beanDefinitionMap中存在..
        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 {//如果不存在
            //抛出一个空指针异常-自定义-Java基础异常
            throw new NullPointerException("没有该bean");
        }
    }
AppMain.java
package com.campus.spring;

import com.campus.spring.component.MonsterDao;
import com.campus.spring.component.MonsterService;
import com.campus.spring.ioc.SpringApplicationContext;
import com.campus.spring.ioc.SpringConfig;



public class AppMain {
    public static void main(String[] args) throws ClassNotFoundException {
        //创建自己的容器
       SpringApplicationContext SpringApplicationContext = new SpringApplicationContext(SpringConfig.class);

        MonsterService monsterService =
                (MonsterService)SpringApplicationContext.getBean("monsterService");
        MonsterService monsterService2 =
                (MonsterService)SpringApplicationContext.getBean("monsterService");

        System.out.println("monsterService=" + monsterService);
        System.out.println("monsterService2=" + monsterService2);

        MonsterDao monsterDao =
                (MonsterDao)SpringApplicationContext.getBean("monsterDao");
        MonsterDao monsterDao2 =
                (MonsterDao)SpringApplicationContext.getBean("monsterDao");

        System.out.println("monsterDao=" + monsterDao);
        System.out.println("monsterDao2=" + monsterDao2);


    }
}
运行结果
class com.campus.spring.ioc.SpringConfig
componentScan= @com.campus.spring.annotation.ComponentScan("com.campus.spring.component")
要扫描的包= com.campus.spring.component
转换后的路径: com/campus/spring/component
resource= file:/E:/%e6%a1%86%e6%9e%b6%e6%8a%80%e6%9c%af%e5%ad%a6%e4%b9%a0/myspring/target/classes/com/campus/spring/component
是一个Spring bean= class com.campus.spring.component.MonsterService 类名= MonsterService
是一个Spring bean= class com.campus.spring.component.MonsterDao 类名= MonsterDao
==============================================
singletonObjects 单例池={}
beanDefinitionMap={monsterService=BeanDefinition{scope='prototype', clazz=class com.campus.spring.component.MonsterService}, monsterDao=BeanDefinition{scope='singleton', clazz=class com.campus.spring.component.MonsterDao}}
==============================================
==============================================
singletonObjects 单例池={monsterDao=com.campus.spring.component.MonsterDao@27fa135a}
beanDefinitionMap={monsterService=BeanDefinition{scope='prototype', clazz=class com.campus.spring.component.MonsterService}, monsterDao=BeanDefinition{scope='singleton', clazz=class com.campus.spring.component.MonsterDao}}
==============================================
Hello World
monsterService=com.campus.spring.component.MonsterService@421faab1
monsterService2=com.campus.spring.component.MonsterService@2b71fc7e
monsterDao=com.campus.spring.component.MonsterDao@27fa135a
monsterDao2=com.campus.spring.component.MonsterDao@27fa135a

注:MonsterDao是单例,所以返回的对象一样(MonsterDao和MonsterDao2)

第四步: 完成依赖注入

Autowired注解

package com.campus.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 {
    //boolean required() default true;
}

MonsterDao.java

package com.campus.spring.component;

import com.campus.spring.annotation.Component;

@Component(value = "monsterDao")
public class MonsterDao {
    public void hi(){
        System.out.println("MonsterDao-- hi()");
    }
}

MonsterService.java

package com.campus.spring.component;


import com.campus.spring.annotation.Autowired;
import com.campus.spring.annotation.Component;
import com.campus.spring.annotation.Scope;

/**
 *	1. 使用@Component("monsterService") 修饰
 *	2. 给该MonsterService 注入到容器设置beanName 为 monsterService
 *	3. 如果没有设置,默认可以以类名首字母小写来玩
 */
@Scope(value = "prototype")
@Component(value="monsterService")
public class MonsterService {

    @Autowired
    private MonsterDao monsterDao;

    public void m1() {
        monsterDao.hi();
    }

}

实现代码:

    for (Field declaredField : clazz.getDeclaredFields()) {
                //2. 判断这个字段是否有@Autowired
                if (declaredField.isAnnotationPresent(Autowired.class)) {
                    //提示一下
                    //处理@Autowired 的required ,很简单
                    //Autowired annotation = declaredField.getAnnotation(Autowired.class)
                    //annotation.required()=> 然后根据true, 是false 进行其它处理..
                    //3. 得到这个字段名字
                    String name = declaredField.getName();
                    //4. 通过getBean方法来获取要组装对象
                    Object bean = getBean(name);
                    //5. 进行组装
                    declaredField.setAccessible(true);//因为属性是pirvate, 需要暴破
                    declaredField.set(instance, bean);
                }
            }
SpringApplicationContext.java
package com.campus.spring.ioc;

import com.campus.spring.annotation.Autowired;
import com.campus.spring.annotation.Component;
import com.campus.spring.annotation.ComponentScan;
import com.campus.spring.annotation.Scope;
import org.springframework.util.StringUtils;


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

/*
SpringApplicationContext 类的作用类似于 Spring原生ioc容器
 */
public class SpringApplicationContext {
    private Class configClass;


    //定义属性BeanDefinitionMap -> 存放BeanDefinition对象
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    //定义属性SingletonObjects -> 存放单例对象
    private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();


    public SpringApplicationContext(Class configClass) {
        setBeanDefinitionsScan(configClass);


        //通过beanDefinitionMap , 初始化singletonObjects 单例池
        //封装成方法
        //遍历所有的beanDefinition对象
        //这里是java基础->集合和枚举
        Enumeration<String> keys = beanDefinitionMap.keys();
        while (keys.hasMoreElements()) {
            //得到beanName
            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("==============================================");
            System.out.println("singletonObjects 单例池=" + singletonObjects);
            System.out.println("beanDefinitionMap=" + beanDefinitionMap);
            System.out.println("==============================================");
        }

    }


    public void setBeanDefinitionsScan(Class configClass) {
        this.configClass = configClass;
        System.out.println(this.configClass);

        //获取要扫描的包
        //1.先得到 SpringConfig配置的@ComponentScan(value = "com.campus.spring.ComponentScan")
        ComponentScan componentScan = (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
        System.out.println("componentScan= " + componentScan);//@com.campus.spring.annotation.ComponentScan("com.campus.spring.component")
        //2.通过componentScan的value =》即要扫描的包
        String path = componentScan.value();
        System.out.println("要扫描的包= " + path);

        //得到要扫描的包下面的所有资源(类.class)
        //1.得到类的加载器
        ClassLoader classLoader = SpringApplicationContext.class.getClassLoader();

        //2.通过类的加载器获取要扫描的包的资源 url =》 类似于一个路径
        path = path.replace(".", "/");
        System.out.println("转换后的路径: " + path);
        URL resource = classLoader.getResource(path);

        System.out.println("resource= " + resource);
        //3.将要加载的资源(.class)路径下的文件进行遍历

        String decodedPath = null;
        try {
            decodedPath = URLDecoder.decode(resource.getFile(), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        File file = new File(decodedPath);
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {

                String fileAbsolutePath = f.getAbsolutePath();
                //这里我们只处理.class文件
                if (fileAbsolutePath.endsWith(".class")) {

                    //1. 获取到类名
                    String className =
                            fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
                    //System.out.println("className=" + className);
                    //2. 获取类的完整的路径(全类名)
                    //解读 path.replace("/",".") =》 com.campus.spring.component.
                    String classFullName = path.replace("/", ".") + "." + className;

                    //3. 判断该类是不是需要注入容器, 就看该类是不是有注解 @Component @Service..
                    try {
                        // aClass.isAnnotationPresent(Component.class) 判断该类是否有 @Component
                        Class<?> clazz = classLoader.loadClass(classFullName);
                        if (clazz.isAnnotationPresent(Component.class)) {
                            System.out.println("是一个Spring bean= " + clazz + " 类名= " + className);

                            //先得到beanName
                            //1. 得到Component注解
                            Component componentAnnotation =
                                    clazz.getDeclaredAnnotation(Component.class);
                            //2. 的配置value值
                            String beanName = componentAnnotation.value();
                            if ("".equals(beanName)) {//如果没有写value
                                //将该类的类名首字母小写作为beanName
                                beanName = StringUtils.uncapitalize(className);
                            }

                            //3.将Bean的信息封装到BeanDefinition对象->放入到BeanDefinitionMap
                            BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setClazz(clazz);
                            //4. 获取Scope值
                            if (clazz.isAnnotationPresent(Scope.class)) {
                                //如果配置了Scope, 获取他配置的值

                                Scope scopeAnnotation = clazz.getDeclaredAnnotation(Scope.class);//scopeAnnotation= @com.campus.spring.annotation.Scope("prototype")
                                //System.out.println("scopeAnnotation= "+scopeAnnotation);
                                beanDefinition.setScope(scopeAnnotation.value());//scopeAnnotation value = prototype
                                // System.out.println("scopeAnnotation value = "+scopeAnnotation.value());
                            } else {
                                //如果没有配置Scope, 就默认的值singleton
                                beanDefinition.setScope("singleton");
                            }

                            //蒋beanDefinition 对象放入到Map
                            beanDefinitionMap.put(beanName, beanDefinition);

                        } else {
                            System.out.println("不是一个Spring bean= " + clazz + " 类名= " + className);
                        }

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


    private Object createBean(String beanName, BeanDefinition beanDefinition) {

        //得到Bean的clazz对象
        Class clazz = beanDefinition.getClazz();
        try {
            //使用反射得到实例
            Object instance = clazz.getDeclaredConstructor().newInstance();

            for (Field declaredField : clazz.getDeclaredFields()) {
                //2. 判断这个字段是否有@Autowired
                if (declaredField.isAnnotationPresent(Autowired.class)) {
                    //提示一下
                    //处理@Autowired 的required ,很简单
                    //Autowired annotation = declaredField.getAnnotation(Autowired.class)
                    //annotation.required()=> 然后根据true, 是false 进行其它处理..
                    //3. 得到这个字段名字
                    String name = declaredField.getName();
                    //4. 通过getBean方法来获取要组装对象
                    Object bean = getBean(name);
                    //5. 进行组装
                    declaredField.setAccessible(true);//因为属性是pirvate, 需要暴破
                    declaredField.set(instance, bean);
                }
            }

            return instance;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        //如何反射创建对象失败
        return null;
    }


    //编写方法getBean(String name),编写方法返回对容器中对象
    public Object getBean(String name) {

        //判断传入的beanName是否在beanDefinitionMap中存在..
        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 {//如果不存在
            //抛出一个空指针异常-小伙伴也可以自定义-Java基础异常
            throw new NullPointerException("没有该bean");
        }
    }
}


AppMain.java

package com.campus.spring;

import com.campus.spring.component.MonsterDao;
import com.campus.spring.component.MonsterService;
import com.campus.spring.ioc.SpringApplicationContext;
import com.campus.spring.ioc.SpringConfig;



public class AppMain {
    public static void main(String[] args) throws ClassNotFoundException {
        //创建自己的容器
       SpringApplicationContext SpringApplicationContext = new SpringApplicationContext(SpringConfig.class);
        System.out.println("Hello World");
        //测试一下依赖注入的功能
        MonsterService monsterService =
                (MonsterService)SpringApplicationContext.getBean("monsterService");

     monsterService.m1();

    }
}

运行结果

Hello World
MonsterDao-- hi()

注:

instance com.campus.spring.component.MonsterService@41906a77

clazz:  class com.campus.spring.component.MonsterService

declaredField(字段有@Autowired的类信息):private com.campus.spring.component.MonsterDao com.campus.spring.component.MonsterService.monsterDao

name(字段名字): monsterDao
bean(要组装的对象): com.campus.spring.component.MonsterDao@27fa135a

第五部:bean 后置处理器实现

补充:bean 的生命周期
● 说明: bean 对象创建是由 JVM 完成的,然后执行如下方法
1. 执行构造器
2. 执行 set 相关方法
3. 调用 bean 的初始化的方法(需要配置),初始化之前可能会调用后置处理器的before方法,在初始化之后可能会调用后置处理器的after方法!!!
4. 使用 bean
5. 当容器关闭时候,调用 bean 的销毁方法(需要配置)

注:在创建好bean实例后,判断是否需要进行初始化(容器中常用的一个方法是:根据该类是否实现某个接口,来判断是否需要执行某个业务逻辑,这其实就算java基础的接口编程实际应用,也就是标记接口

1.“创建好bean实例后,判断是否需要进行初始化”代码演示


1.1.InitializingBean接口
package com.campus.spring.processor;

/**
 * 1. 我们根据原生Spring 定义了一个InitializingBean
 * 2. 该InitializingBean接口有一个方法void afterPropertiesSet() throws Exception;
 * 3. afterPropertiesSet() 在Bean的 setter后执行,即就是我们原来的初始化方法
 * 4. 当一个Bean实现这个接口后,就实现afterPropertiesSet() , 这个方法就是初始化方法
 */
public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}

1.2.SpringApplicationContext.java
package com.campus.spring.ioc;

import com.campus.spring.annotation.Autowired;
import com.campus.spring.annotation.Component;
import com.campus.spring.annotation.ComponentScan;
import com.campus.spring.annotation.Scope;
import com.campus.spring.processor.InitializingBean;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.util.StringUtils;


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

/*
SpringApplicationContext 类的作用类似于 Spring原生ioc容器
 */
public class SpringApplicationContext {
    private Class configClass;


    //定义属性BeanDefinitionMap -> 存放BeanDefinition对象
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    //定义属性SingletonObjects -> 存放单例对象
    private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();


    public SpringApplicationContext(Class configClass) {
        setBeanDefinitionsScan(configClass);


        //通过beanDefinitionMap , 初始化singletonObjects 单例池
        //封装成方法
        //遍历所有的beanDefinition对象
        //这里是java基础->集合和枚举
        Enumeration<String> keys = beanDefinitionMap.keys();
        while (keys.hasMoreElements()) {
            //得到beanName
            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("==============================================");
            System.out.println("singletonObjects 单例池=" + singletonObjects);
            System.out.println("beanDefinitionMap=" + beanDefinitionMap);
            System.out.println("==============================================");
        }

    }


    public void setBeanDefinitionsScan(Class configClass) {
        this.configClass = configClass;
        System.out.println(this.configClass);

        //获取要扫描的包
        //1.先得到 SpringConfig配置的@ComponentScan(value = "com.campus.spring.ComponentScan")
        ComponentScan componentScan = (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
        System.out.println("componentScan= " + componentScan);//@com.campus.spring.annotation.ComponentScan("com.campus.spring.component")
        //2.通过componentScan的value =》即要扫描的包
        String path = componentScan.value();
        System.out.println("要扫描的包= " + path);

        //得到要扫描的包下面的所有资源(类.class)
        //1.得到类的加载器
        ClassLoader classLoader = SpringApplicationContext.class.getClassLoader();

        //2.通过类的加载器获取要扫描的包的资源 url =》 类似于一个路径
        path = path.replace(".", "/");
        System.out.println("转换后的路径: " + path);
        URL resource = classLoader.getResource(path);

        System.out.println("resource= " + resource);
        //3.将要加载的资源(.class)路径下的文件进行遍历

        String decodedPath = null;
        try {
            decodedPath = URLDecoder.decode(resource.getFile(), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        File file = new File(decodedPath);
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {

                String fileAbsolutePath = f.getAbsolutePath();
                //这里我们只处理.class文件
                if (fileAbsolutePath.endsWith(".class")) {

                    //1. 获取到类名
                    String className =
                            fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
                    //System.out.println("className=" + className);
                    //2. 获取类的完整的路径(全类名)
                    //解读 path.replace("/",".") =》 com.campus.spring.component.
                    String classFullName = path.replace("/", ".") + "." + className;

                    //3. 判断该类是不是需要注入容器, 就看该类是不是有注解 @Component @Service..
                    try {
                        // aClass.isAnnotationPresent(Component.class) 判断该类是否有 @Component
                        Class<?> clazz = classLoader.loadClass(classFullName);
                        if (clazz.isAnnotationPresent(Component.class)) {
                            System.out.println("是一个Spring bean= " + clazz + " 类名= " + className);

                            //先得到beanName
                            //1. 得到Component注解
                            Component componentAnnotation =
                                    clazz.getDeclaredAnnotation(Component.class);
                            //2. 的配置value值
                            String beanName = componentAnnotation.value();
                            if ("".equals(beanName)) {//如果没有写value
                                //将该类的类名首字母小写作为beanName
                                beanName = StringUtils.uncapitalize(className);
                            }

                            //3.将Bean的信息封装到BeanDefinition对象->放入到BeanDefinitionMap
                            BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setClazz(clazz);
                            //4. 获取Scope值
                            if (clazz.isAnnotationPresent(Scope.class)) {
                                //如果配置了Scope, 获取他配置的值

                                Scope scopeAnnotation = clazz.getDeclaredAnnotation(Scope.class);//scopeAnnotation= @com.campus.spring.annotation.Scope("prototype")
                                //System.out.println("scopeAnnotation= "+scopeAnnotation);
                                beanDefinition.setScope(scopeAnnotation.value());//scopeAnnotation value = prototype
                                // System.out.println("scopeAnnotation value = "+scopeAnnotation.value());
                            } else {
                                //如果没有配置Scope, 就默认的值singleton
                                beanDefinition.setScope("singleton");
                            }

                            //蒋beanDefinition 对象放入到Map
                            beanDefinitionMap.put(beanName, beanDefinition);

                        } else {
                            System.out.println("不是一个Spring bean= " + clazz + " 类名= " + className);
                        }

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


    private Object createBean(String beanName, BeanDefinition beanDefinition) {

        //得到Bean的clazz对象
        Class clazz = beanDefinition.getClazz();
        try {
            //使用反射得到实例
            Object instance = clazz.getDeclaredConstructor().newInstance();

            for (Field declaredField : clazz.getDeclaredFields()) {
                //2. 判断这个字段是否有@Autowired
                if (declaredField.isAnnotationPresent(Autowired.class)) {
                    //提示一下
                    //处理@Autowired 的required ,很简单
                    //Autowired annotation = declaredField.getAnnotation(Autowired.class)
                    //annotation.required()=> 然后根据true, 是false 进行其它处理..
                    //3. 得到这个字段名字
                    String name = declaredField.getName();
                    //4. 通过getBean方法来获取要组装对象
                    Object bean = getBean(name);
                    //5. 进行组装
                    declaredField.setAccessible(true);//因为属性是pirvate, 需要暴破
                    declaredField.set(instance, bean);

                }
            }
        System.out.println("===创建好bean实例===="+ instance);

            //这里判断是否要执行Bean初始化方法
            //1. 判断当前创建的Bean对象是否实现了InitializingBean
            //2. instanceof  表判断某个对象的运行类型是不是 某个类型 或者 某个类型的子类型
            //3. 这里就使用到接口编程
            if (instance instanceof InitializingBean) {
                //3.将instance转成InitializingBean类型
                try {
                    ((InitializingBean) instance).afterPropertiesSet();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            return instance;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        //如何反射创建对象失败
        return null;
    }


    //编写方法getBean(String name),编写方法返回对容器中对象
    public Object getBean(String name) {

        //判断传入的beanName是否在beanDefinitionMap中存在..
        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 {//如果不存在
            //抛出一个空指针异常-小伙伴也可以自定义-Java基础异常
            throw new NullPointerException("没有该bean");
        }
    }
}


1.3.运行结果:
注:
MonsterDao 没有实现了InitializingBean 接口(implements InitializingBean) ,而MonsterService实现了接口(implements InitializingBean),所以MonsterService 初始化方法被调用

2.实现后置处理器方法的调用

BeanPostProcessor接口
package com.campus.spring.processor;

/**
 * 1. 参考原生Spring容器定义一个接口BeanPostProcessor
 * 2. 该接口有两个方法postProcessBeforeInitialization 和 postProcessAfterInitialization
 * 3. 这两个方法,会对Spring容器的所有Bean生效, 已经是切面编程的概念.
 */
public interface BeanPostProcessor {

    /**
     * 1. postProcessBeforeInitialization在Bean的初始化方法前调用
     * @param bean
     * @param beanName
     * @return
     */
    default Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }

    /**
     * 1. postProcessAfterInitialization在Bean的初始化方法后调用
     * @param bean
     * @param beanName
     * @return
     */
    default Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }
}

注:接口有两个方法postProcessBeforeInitializationpostProcessAfterInitialization,这两个方法,会对Spring容器的所有Bean生效,

 com.campus.spring.component.myBeanPostProcessor.java(后置处理器)

package com.campus.spring.component;

import com.campus.spring.annotation.Component;


/**
 * 1. 这是我们自己的一个后置处理器
 * 2. 实现了BeanPostProcessor
 * 3. 我们可以重写before和after方法
 * 4. 在Spring容器中,仍然把HspBeanPostProcessor当做一个Bean对象, 要在注入到容器
 * 5. @Component 标识
 * 6. 我们要让HspBeanPostProcessor成为真正的后置处理器, 需要在容器中加入业务代码
 * 7. 还要考虑多个后置处理器对象注入到容器问题
 */
@Component
public class myBeanPostProcessor implements com.campus.spring.processor.BeanPostProcessor {

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

        System.out.println("后置处理器HspBeanPostProcessor Before调用 bean类型="
                + bean.getClass() + " bean的名字=" + beanName);
        return bean;
    }

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

        System.out.println("后置处理器HspBeanPostProcessor After调用 bean类型="
                + bean.getClass() + " bean的名字=" + beanName);

        return bean;
    }
}
SpringApplicationContext.java
package com.campus.spring.ioc;

import com.campus.spring.annotation.Autowired;
import com.campus.spring.annotation.Component;
import com.campus.spring.annotation.ComponentScan;
import com.campus.spring.annotation.Scope;
import com.campus.spring.processor.BeanPostProcessor;
import com.campus.spring.processor.InitializingBean;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.util.StringUtils;


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

/*
SpringApplicationContext 类的作用类似于 Spring原生ioc容器
 */
public class SpringApplicationContext {
    private Class configClass;


    //定义属性BeanDefinitionMap -> 存放BeanDefinition对象
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    //定义属性SingletonObjects -> 存放单例对象
    private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();


    //定义一个属性beanPostProcessorList, => 存放后置处理器
    private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();


    public SpringApplicationContext(Class configClass) {
        setBeanDefinitionsScan(configClass);


        //通过beanDefinitionMap , 初始化singletonObjects 单例池
        //封装成方法
        //遍历所有的beanDefinition对象
        //这里是java基础->集合和枚举
        Enumeration<String> keys = beanDefinitionMap.keys();
        while (keys.hasMoreElements()) {
            //得到beanName
            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("==============================================");
            System.out.println("singletonObjects 单例池=" + singletonObjects);
            System.out.println("beanDefinitionMap=" + beanDefinitionMap);
            System.out.println("==============================================");
        }

    }


    public void setBeanDefinitionsScan(Class configClass) {
        this.configClass = configClass;
        System.out.println(this.configClass);

        //获取要扫描的包
        //1.先得到 SpringConfig配置的@ComponentScan(value = "com.campus.spring.ComponentScan")
        ComponentScan componentScan = (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
        System.out.println("componentScan= " + componentScan);//@com.campus.spring.annotation.ComponentScan("com.campus.spring.component")
        //2.通过componentScan的value =》即要扫描的包
        String path = componentScan.value();
        System.out.println("要扫描的包= " + path);

        //得到要扫描的包下面的所有资源(类.class)
        //1.得到类的加载器
        ClassLoader classLoader = SpringApplicationContext.class.getClassLoader();

        //2.通过类的加载器获取要扫描的包的资源 url =》 类似于一个路径
        path = path.replace(".", "/");
        System.out.println("转换后的路径: " + path);
        URL resource = classLoader.getResource(path);

        System.out.println("resource= " + resource);
        //3.将要加载的资源(.class)路径下的文件进行遍历

        String decodedPath = null;
        try {
            decodedPath = URLDecoder.decode(resource.getFile(), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        File file = new File(decodedPath);
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {

                String fileAbsolutePath = f.getAbsolutePath();
                //这里我们只处理.class文件
                if (fileAbsolutePath.endsWith(".class")) {

                    //1. 获取到类名
                    String className =
                            fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
                    //System.out.println("className=" + className);
                    //2. 获取类的完整的路径(全类名)
                    //解读 path.replace("/",".") =》 com.campus.spring.component.
                    String classFullName = path.replace("/", ".") + "." + className;

                    //3. 判断该类是不是需要注入容器, 就看该类是不是有注解 @Component @Service..
                    try {
                        // aClass.isAnnotationPresent(Component.class) 判断该类是否有 @Component
                        Class<?> clazz = classLoader.loadClass(classFullName);
                        if (clazz.isAnnotationPresent(Component.class)) {
                            System.out.println("是一个Spring bean= " + clazz + " 类名= " + className);


                            //1. 为了方便,将后置处理器放入到一个ArrayList
                            //2. 如果发现是一个后置处理器, 放入到 beanPostProcessorList
                            //3. 在原生的Spring容器中, 对后置处理器还是走的getBean, createBean
                            //   , 但是需要我们在singletonObjects 加入相应的业务逻辑
                            //4. 因为这里我们是为了讲解后置处理去的机制,我就简化

                            //判断当前的这个clazz有没有实现BeanPostProcessor
                            //说明, 这里我们不能使用 instanceof 来判断clazz是否实现了BeanPostProcessor
                            //原因: clazz不是一个实例对象,而是一个类对象/clazz, 使用isAssignableFrom
                            //小伙伴将其当做一个语法理解
                            if (BeanPostProcessor.class.isAssignableFrom(clazz)) {

                                BeanPostProcessor beanPostProcessor =
                                        (BeanPostProcessor) clazz.newInstance();
                                //放入到beanPostProcessorList
                                beanPostProcessorList.add(beanPostProcessor);
                                continue;
                            }


                            //先得到beanName
                            //1. 得到Component注解
                            Component componentAnnotation =
                                    clazz.getDeclaredAnnotation(Component.class);
                            //2. 的配置value值
                            String beanName = componentAnnotation.value();
                            if ("".equals(beanName)) {//如果没有写value
                                //将该类的类名首字母小写作为beanName
                                beanName = StringUtils.uncapitalize(className);
                            }

                            //3.将Bean的信息封装到BeanDefinition对象->放入到BeanDefinitionMap
                            BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setClazz(clazz);
                            //4. 获取Scope值
                            if (clazz.isAnnotationPresent(Scope.class)) {
                                //如果配置了Scope, 获取他配置的值

                                Scope scopeAnnotation = clazz.getDeclaredAnnotation(Scope.class);//scopeAnnotation= @com.campus.spring.annotation.Scope("prototype")
                                //System.out.println("scopeAnnotation= "+scopeAnnotation);
                                beanDefinition.setScope(scopeAnnotation.value());//scopeAnnotation value = prototype
                                // System.out.println("scopeAnnotation value = "+scopeAnnotation.value());
                            } else {
                                //如果没有配置Scope, 就默认的值singleton
                                beanDefinition.setScope("singleton");
                            }

                            //蒋beanDefinition 对象放入到Map
                            beanDefinitionMap.put(beanName, beanDefinition);

                        } else {
                            System.out.println("不是一个Spring bean= " + clazz + " 类名= " + className);
                        }

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


    private Object createBean(String beanName, BeanDefinition beanDefinition) {

        //得到Bean的clazz对象
        Class clazz = beanDefinition.getClazz();
        try {
            //使用反射得到实例
            Object instance = clazz.getDeclaredConstructor().newInstance();

            for (Field declaredField : clazz.getDeclaredFields()) {
                //2. 判断这个字段是否有@Autowired
                if (declaredField.isAnnotationPresent(Autowired.class)) {
                    //提示一下
                    //处理@Autowired 的required ,很简单
                    //Autowired annotation = declaredField.getAnnotation(Autowired.class)
                    //annotation.required()=> 然后根据true, 是false 进行其它处理..
                    //3. 得到这个字段名字
                    String name = declaredField.getName();
                    //4. 通过getBean方法来获取要组装对象
                    Object bean = getBean(name);
                    //5. 进行组装
                    declaredField.setAccessible(true);//因为属性是pirvate, 需要暴破
                    declaredField.set(instance, bean);

                }
            }
            System.out.println("-------------------------------------------------------------------------------");
        System.out.println("===创建好bean实例===="+ instance);
            System.out.println("-------------------------------------------------------------------------------");

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


            //这里判断是否要执行Bean初始化方法
            //1. 判断当前创建的Bean对象是否实现了InitializingBean
            //2. instanceof  表判断某个对象的运行类型是不是 某个类型 或者 某个类型的子类型
            //3. 这里就使用到接口编程
            if (instance instanceof InitializingBean) {
                //3.将instance转成InitializingBean类型
                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;
                }
            }


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


        //如何反射创建对象失败
        return null;
    }


    //编写方法getBean(String name),编写方法返回对容器中对象
    public Object getBean(String name) {

        //判断传入的beanName是否在beanDefinitionMap中存在..
        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 {//如果不存在
            //抛出一个空指针异常-小伙伴也可以自定义-Java基础异常
            throw new NullPointerException("没有该bean");
        }
    }
}


SpringApplicationContext新增代码:

    //定义一个属性beanPostProcessorList, => 存放后置处理器
    private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();

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


            //这里判断是否要执行Bean初始化方法
            //1. 判断当前创建的Bean对象是否实现了InitializingBean
            //2. instanceof  表判断某个对象的运行类型是不是 某个类型 或者 某个类型的子类型
            //3. 这里就使用到接口编程
            if (instance instanceof InitializingBean) {
                //3.将instance转成InitializingBean类型
                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;
                }
            }

运行结果:

第六步:实现AOP机制

com.campus.spring.annotation.Aspect注解

package com.campus.spring.annotation;

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 Aspect {
    String value() default "";
}

com.campus.spring.processor.BeanPostProcessor接口

package com.campus.spring.processor;

/**
 * 1. 参考原生Spring容器定义一个接口BeanPostProcessor
 * 2. 该接口有两个方法postProcessBeforeInitialization 和 postProcessAfterInitialization
 * 3. 这两个方法,会对Spring容器的所有Bean生效, 已经是切面编程的概念.
 */
public interface BeanPostProcessor {

    /**
     * 1. postProcessBeforeInitialization在Bean的初始化方法前调用
     * @param bean
     * @param beanName
     * @return
     */
    default Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }

    /**
     * 1. postProcessAfterInitialization在Bean的初始化方法后调用
     * @param bean
     * @param beanName
     * @return
     */
    default Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }
}

com.campus.spring.processor.myBeanPostProcessor.java(后置处理器)

package com.campus.spring.component;

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

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

/**
 * 1. 我们自己的一个后置处理器
 * 2. 实现了BeanPostProcessor
 * 3. 我们可以重写before和after方法
 * 4. 在Spring容器中,仍然把HspBeanPostProcessor当做一个Bean对象, 要在注入到容器
 * 5. @Component 标识
 * 6. 我们要让BeanPostProcessor成为真正的后置处理器, 需要在容器中加入业务代码
 * 7. 还要考虑多个后置处理器对象注入到容器问题
 */
@Component
public class myBeanPostProcessor implements BeanPostProcessor {

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

        System.out.println("后置处理器HspBeanPostProcessor Before调用 bean类型="
                + bean.getClass() + " bean的名字=" + beanName);
        return bean;
    }

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

        System.out.println("后置处理器HspBeanPostProcessor After调用 bean类型="
                + bean.getClass() + " bean的名字=" + beanName);

        //实现AOP, 返回代理对象, 即对Bean进行包装
        if ("smartDog".equals(beanName)) {
            //使用Jdk的动态代理,返回返回bean的代理对象,我的另外一篇AOP文章中有这个知识点
            Object proxyInstance = Proxy.newProxyInstance(BeanPostProcessor.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
            return proxyInstance;
        }
        //如果不需要AOP, 返回 bean
        return bean;
    }
}

注:

使用Jdk的动态代理,返回返回bean的代理对象,我的另外一篇"JAVA----Spring的AOP和动态代理"文章中有这个知识点!!!

com.campus.spring.component.SmartAnimalAspect

package com.campus.spring.component;

import com.campus.spring.annotation.*;



/**
 SmartAnimalAspect当做一个切面类来使用

 */

public class SmartAnimalAspect {

    public static void showBeginLog() {

        System.out.println("前置通知..");
    }

    public static void showSuccessLog() {

        System.out.println("返回通知..");
    }
}

com.campus.spring.ioc.SmartAnimalable

package com.campus.spring.ioc;


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


com.campus.spring.component.SmartDog

package com.campus.spring.component;

import com.campus.spring.annotation.Component;
import com.campus.spring.ioc.SmartAnimalable;

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

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

SpringApplicationContext.java、

package com.campus.spring.ioc;

import com.campus.spring.annotation.Autowired;
import com.campus.spring.annotation.Component;
import com.campus.spring.annotation.ComponentScan;
import com.campus.spring.annotation.Scope;
import com.campus.spring.processor.BeanPostProcessor;
import com.campus.spring.processor.InitializingBean;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.util.StringUtils;


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

/*
SpringApplicationContext 类的作用类似于 Spring原生ioc容器
 */
public class SpringApplicationContext {
    private Class configClass;


    //定义属性BeanDefinitionMap -> 存放BeanDefinition对象
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    //定义属性SingletonObjects -> 存放单例对象
    private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();


    //定义一个属性beanPostProcessorList, => 存放后置处理器
    private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();


    public SpringApplicationContext(Class configClass) {
        setBeanDefinitionsScan(configClass);


        //通过beanDefinitionMap , 初始化singletonObjects 单例池
        //封装成方法
        //遍历所有的beanDefinition对象
        //这里是java基础->集合和枚举
        Enumeration<String> keys = beanDefinitionMap.keys();
        while (keys.hasMoreElements()) {
            //得到beanName
            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("==============================================");
            System.out.println("singletonObjects 单例池=" + singletonObjects);
            System.out.println("beanDefinitionMap=" + beanDefinitionMap);
            System.out.println("==============================================");
        }

    }


    public void setBeanDefinitionsScan(Class configClass) {
        this.configClass = configClass;
        System.out.println(this.configClass);

        //获取要扫描的包
        //1.先得到 SpringConfig配置的@ComponentScan(value = "com.campus.spring.ComponentScan")
        ComponentScan componentScan = (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
        System.out.println("componentScan= " + componentScan);//@com.campus.spring.annotation.ComponentScan("com.campus.spring.component")
        //2.通过componentScan的value =》即要扫描的包
        String path = componentScan.value();
        System.out.println("要扫描的包= " + path);

        //得到要扫描的包下面的所有资源(类.class)
        //1.得到类的加载器
        ClassLoader classLoader = SpringApplicationContext.class.getClassLoader();

        //2.通过类的加载器获取要扫描的包的资源 url =》 类似于一个路径
        path = path.replace(".", "/");
        System.out.println("转换后的路径: " + path);
        URL resource = classLoader.getResource(path);

        System.out.println("resource= " + resource);
        //3.将要加载的资源(.class)路径下的文件进行遍历

        String decodedPath = null;
        try {
            decodedPath = URLDecoder.decode(resource.getFile(), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        File file = new File(decodedPath);
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {

                String fileAbsolutePath = f.getAbsolutePath();
                //这里我们只处理.class文件
                if (fileAbsolutePath.endsWith(".class")) {

                    //1. 获取到类名
                    String className =
                            fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
                    //System.out.println("className=" + className);
                    //2. 获取类的完整的路径(全类名)
                    //解读 path.replace("/",".") =》 com.campus.spring.component.
                    String classFullName = path.replace("/", ".") + "." + className;

                    //3. 判断该类是不是需要注入容器, 就看该类是不是有注解 @Component @Service..
                    try {
                        // aClass.isAnnotationPresent(Component.class) 判断该类是否有 @Component
                        Class<?> clazz = classLoader.loadClass(classFullName);
                        if (clazz.isAnnotationPresent(Component.class)) {
                            System.out.println("是一个Spring bean= " + clazz + " 类名= " + className);


                            //1. 为了方便,将后置处理器放入到一个ArrayList
                            //2. 如果发现是一个后置处理器, 放入到 beanPostProcessorList
                            //3. 在原生的Spring容器中, 对后置处理器还是走的getBean, createBean
                            //   , 但是需要我们在singletonObjects 加入相应的业务逻辑
                            //4. 因为这里我们是为了讲解后置处理去的机制,我就简化

                            //判断当前的这个clazz有没有实现BeanPostProcessor
                            //说明, 这里我们不能使用 instanceof 来判断clazz是否实现了BeanPostProcessor
                            //原因: clazz不是一个实例对象,而是一个类对象/clazz, 使用isAssignableFrom
                            if (BeanPostProcessor.class.isAssignableFrom(clazz)) {

                                BeanPostProcessor beanPostProcessor =
                                        (BeanPostProcessor) clazz.newInstance();
                                //放入到beanPostProcessorList
                                beanPostProcessorList.add(beanPostProcessor);
                                continue;
                            }


                            //先得到beanName
                            //1. 得到Component注解
                            Component componentAnnotation =
                                    clazz.getDeclaredAnnotation(Component.class);
                            //2. 的配置value值
                            String beanName = componentAnnotation.value();
                            if ("".equals(beanName)) {//如果没有写value
                                //将该类的类名首字母小写作为beanName
                                beanName = StringUtils.uncapitalize(className);
                            }

                            //3.将Bean的信息封装到BeanDefinition对象->放入到BeanDefinitionMap
                            BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setClazz(clazz);
                            //4. 获取Scope值
                            if (clazz.isAnnotationPresent(Scope.class)) {
                                //如果配置了Scope, 获取他配置的值

                                Scope scopeAnnotation = clazz.getDeclaredAnnotation(Scope.class);//scopeAnnotation= @com.campus.spring.annotation.Scope("prototype")
                                //System.out.println("scopeAnnotation= "+scopeAnnotation);
                                beanDefinition.setScope(scopeAnnotation.value());//scopeAnnotation value = prototype
                                // System.out.println("scopeAnnotation value = "+scopeAnnotation.value());
                            } else {
                                //如果没有配置Scope, 就默认的值singleton
                                beanDefinition.setScope("singleton");
                            }

                            //蒋beanDefinition 对象放入到Map
                            beanDefinitionMap.put(beanName, beanDefinition);

                        } else {
                            System.out.println("不是一个Spring bean= " + clazz + " 类名= " + className);
                        }

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


    private Object createBean(String beanName, BeanDefinition beanDefinition) {

        //得到Bean的clazz对象
        Class clazz = beanDefinition.getClazz();
        try {
            //使用反射得到实例
            Object instance = clazz.getDeclaredConstructor().newInstance();

            for (Field declaredField : clazz.getDeclaredFields()) {
                //2. 判断这个字段是否有@Autowired
                if (declaredField.isAnnotationPresent(Autowired.class)) {
                    //提示一下
                    //处理@Autowired 的required ,很简单
                    //Autowired annotation = declaredField.getAnnotation(Autowired.class)
                    //annotation.required()=> 然后根据true, 是false 进行其它处理..
                    //3. 得到这个字段名字
                    String name = declaredField.getName();
                    //4. 通过getBean方法来获取要组装对象
                    Object bean = getBean(name);
                    //5. 进行组装
                    declaredField.setAccessible(true);//因为属性是pirvate, 需要暴破
                    declaredField.set(instance, bean);

                }
            }
            System.out.println("-------------------------------------------------------------------------------");
        System.out.println("===创建好bean实例===="+ instance);
            System.out.println("-------------------------------------------------------------------------------");

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


            //这里判断是否要执行Bean初始化方法
            //1. 判断当前创建的Bean对象是否实现了InitializingBean
            //2. instanceof  表判断某个对象的运行类型是不是 某个类型 或者 某个类型的子类型
            //3. 这里就使用到接口编程
            if (instance instanceof InitializingBean) {
                //3.将instance转成InitializingBean类型
                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;
                }
            }


            return instance;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } //如何反射创建对象失败
        return null;
    }


    //编写方法getBean(String name),编写方法返回对容器中对象
    public Object getBean(String name) {

        //判断传入的beanName是否在beanDefinitionMap中存在..
        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 {//如果不存在
            //抛出一个空指针异常-我们可以自定义-Java基础异常
            throw new NullPointerException("没有该bean");
        }
    }
}


AppMain.java

package com.campus.spring;

import com.campus.spring.component.MonsterDao;
import com.campus.spring.component.MonsterService;
import com.campus.spring.ioc.SmartAnimalable;
import com.campus.spring.ioc.SpringApplicationContext;
import com.campus.spring.ioc.SpringConfig;



public class AppMain {
    public static void main(String[] args) throws ClassNotFoundException {
        //创建自己的容器
       SpringApplicationContext SpringApplicationContext = new SpringApplicationContext(SpringConfig.class);
        System.out.println("Hello World");
        //测试一下依赖注入的功能
        MonsterService monsterService =
                (MonsterService)SpringApplicationContext.getBean("monsterService");

     monsterService.m1();
//
//        MonsterService monsterService =
//                (MonsterService)SpringApplicationContext.getBean("monsterService");
//        MonsterService monsterService2 =
//                (MonsterService)SpringApplicationContext.getBean("monsterService");
//
//        System.out.println("monsterService=" + monsterService);
//        System.out.println("monsterService2=" + monsterService2);
//
//        MonsterDao monsterDao =
//                (MonsterDao)SpringApplicationContext.getBean("monsterDao");
//        MonsterDao monsterDao2 =
//                (MonsterDao)SpringApplicationContext.getBean("monsterDao");
//
//        System.out.println("monsterDao=" + monsterDao);
//        System.out.println("monsterDao2=" + monsterDao2);

//        这里我们测试一下AOP机制是否生效了
        SmartAnimalable smartDog = (SmartAnimalable)SpringApplicationContext.getBean("smartDog");
        System.out.println("smartDog=" + smartDog.getClass());

        smartDog.getSum(10, 2);

        smartDog.getSub(10,2);

       System.out.println("ok");
    }
}

运行结果(主要代码结果):

smartDog=class jdk.proxy2.$Proxy4
method=getSum
前置通知..
SmartDog-getSum-res=12.0
返回通知..
method=getSub
SmartDog-getSub-res=8.0
ok