手写spring-仿照spring

1,遍及一个小常识

UserService.class
@Component
public class UserService{
public void test(){
System.out.println("test")
}
}
Test.class
    public class Test{
        public static void main(String[] args){
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
            UserService userService = (UserService)context.getBean("userService");
        }
    }

上述userService bean是什么时分创立得呢?

这时分要检查UserService类上是否含有@Lazy懒加载这个注解(作用是在需求运用该bean的时分就创立)

非懒加载的单例bean,bean就会在spring发动的时分,就会将非懒加载的单例bean全部创立出来,然后直接经过getBean直接去获取bean

相似下面

//非懒加载的单例bean   
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
            UserService userService = (UserService)context.getBean("userService");

还有一种原型bean

UserService.class
@Component
@Scope("prototype")
public class UserService{
public void test(){
System.out.println("test")
}
}

原型bean在每一次getBean的时分会创立,每一次getBean时都会创立一个新目标出现

原型bean便是多例,每一次去get去拿都是一个新目标


2,开端创立一个一般maven工程,开端仿照spring准备工作

这个是项目的初始目录

带你走进spring源码----浅看spring底层实现

写在spring包底下的东西就仿照是spring内部的东西

llb包下的东西便是运用spring的办法

//spring包下的Component
    /*
1、RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时分,注解被遗弃;
2、RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时分被遗弃,这是默许的生命周期;
3、RetentionPolicy.RUNTIME:注解不只被保存到class文件中,jvm加载class文件之后,依然存在;
这3个生命周期别离对应于:Java源文件(.java文件) ---> .class文件 ---> 内存中的字节码。
那怎样来挑选合适的注解生命周期呢?
首要要清晰生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的当地后者一定也能作用。一般假如需求在运转时去动态获取注解信息,那只能用 RUNTIME 注解;假如要在编译时进行一些预处理操作,比方生成一些辅佐代码(如 ButterKnife),就用 CLASS注解;假如仅仅做一些检查性的操作,比方 @Override 和 @SuppressWarnings,则可选用 SOURCE 注解。
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)//该注解能够用在类上
//用来给bean创立一个姓名
public @interface Component {
    String value() default "";
}
//spring包下的componentScan
/*
1、RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时分,注解被遗弃;
2、RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时分被遗弃,这是默许的生命周期;
3、RetentionPolicy.RUNTIME:注解不只被保存到class文件中,jvm加载class文件之后,依然存在;
这3个生命周期别离对应于:Java源文件(.java文件) ---> .class文件 ---> 内存中的字节码。
那怎样来挑选合适的注解生命周期呢?
首要要清晰生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的当地后者一定也能作用。一般假如需求在运转时去动态获取注解信息,那只能用 RUNTIME 注解;假如要在编译时进行一些预处理操作,比方生成一些辅佐代码(如 ButterKnife),就用 CLASS注解;假如仅仅做一些检查性的操作,比方 @Override 和 @SuppressWarnings,则可选用 SOURCE 注解。
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)//该注解能够用在类上
//用来扫描bean
public @interface ComponentScan {
    String value() default "";
}
//spring包下的LLBApplicationContext
public class LLBApplicationContext {
    //为了完结TestLLBApplicationContext()里边接纳参数
    private Class configClass;//界说一个装备类参数
    public LLBApplicationContext(Class configClass) {
        this.configClass = configClass;
    }
    //为了完结context.getBean   在容器中获取bean目标
    public Object getBean(String userService) {
        return null;
    }
}

接下来是llb包下的service里的UserService

@Component("userService")//给bean取一个姓名userService
public class UserService {
    public void test(){
        System.out.println("test");
    }
}
//llb包下的AppConfig
@ComponentScan("com.hhxy.llb.service")//扫描com.hhxy.llb.service下面的内容
public class AppConfig {
}
//llb包下的test
public class Test {
    public static void main(String[] args) {
        //仿照
        /**
         * //非懒加载的单例bean
         * AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
         * UserService userService = (UserService)context.getBean("userService");
         * 写法
         */
        LLBApplicationContext context = new LLBApplicationContext(AppConfig.class);
        UserService userService = (UserService) context.getBean("userService");
        userService.test();
    }
}

3,开端仿照spring

条件咱们先疏忽懒加载

首要咱们要进行扫描

假设llb下service包下还存在一个orderService

public class OrderService {
    public void test(){
        System.out.println("test");
    }
}

图上APPConfig,咱们会让AppConfig先去扫描com.hhxy.llb.service包下面到底哪些类是单例bean

所以在创立单例bean之前需求进行扫描

//创立单例bean    
LLBApplicationContext context = new LLBApplicationContext(AppConfig.class);

这些操作要在LLBApplicationContext的结构办法中完结 怎样让他扫描呢

在LLBApplicationContext中结构办法改造成如下
  public LLBApplicationContext(Class configClass) {
        this.configClass = configClass;
        if (configClass.isAnnotationPresent(ComponentScan.class)){//先判别该类上是否界说了ComponentScan注解
            //界说了就接纳ComponentScan的信息
            ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            //在从ComponentScan中获取扫描途径
            String path = componentScanAnnotation.value();
            System.out.println(path);
        }
    }

现在咱们运转一下写的程序看看是否能获取到扫描途径

带你走进spring源码----浅看spring底层实现

控制台输出

com.hhxy.llb.service   //这个便是扫描途径
//下面这个是报错,由于咱们Test的getBean办法内部是return null
Exception in thread "main" java.lang.NullPointerException
	at com.hhxy.llb.Test.main(Test.java:17)

这儿的扫描途径是咱们的写的源文件是.java文件

咱们应该取的是编译后文件.class文件(target下的)

应该是依据com.hhxy.llb.service 找到

带你走进spring源码----浅看spring底层实现

找到这个service下一切的.class文件把他们解析看看谁的类上含有注解

所以咱们应该怎么找到这个class下的扫描途径呢

运转Java程序能够注意到
"C:\Program Files\Java\jdk1.8.0_201\bin\java.exe" "-javaagent:D:\软件\IntelliJ IDEA 2020.2.3\IntelliJ IDEA 2020.2.3\lib\idea_rt.jar=12760:D:\软件\IntelliJ IDEA 2020.2.3\IntelliJ IDEA 2020.2.3\bin" -Dfile.encoding=UTF-8 
-classpath "C:\Program Files\Java\jdk1.8.0_201\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\rt.jar;C:\hhxy\spring_demo\target\classes" com.hhxy.llb.Test
com.hhxy.llb.service

倒数榜首、二行C:\hhxy\spring_demo\target\classes” com.hhxy.llb.Test com.hhxy.llb.service与咱们class下的类相似 为什么有什么原理么

与类加载器有关

那些目录是它们加载的呢

BootStrap ClassLoader ———–>jre/lib

ExtensionClassLoader ————>jre/ext/bin

AppClassLoader ————->是上述classpath后边指定的(差不多便是办理target目录)

//在spring下增加Scope类
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)//该注解能够用在类上
//用来给bean创立一个姓名
public @interface Scope {
    String value() default "";
}
//改造com.hhxy.llb.service
@Component("userService")
@Scope("singleton")
public class UserService {
    public void test(){
        System.out.println("test");
    }
}
//改造LLBApplicationContext
public class LLBApplicationContext {
    //为了完结TestLLBApplicationContext()里边接纳参数
    private Class configClass;//界说一个装备类参数
    public LLBApplicationContext(Class configClass) {
        this.configClass = configClass;
        if (configClass.isAnnotationPresent(ComponentScan.class)){//先判别该类上是否界说了ComponentScan注解
            //界说了就接纳ComponentScan的信息
            ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            //在从ComponentScan中获取扫描途径
            String path = componentScanAnnotation.value();
            String replacePath = path.replace(".", "/");//com/hhxy/llb/service  相对途径
//            System.out.println(replacePath);
//            System.out.println("----------------------------------------------------------------");
            ClassLoader classLoader = LLBApplicationContext.class.getClassLoader();
            URL resource = classLoader.getResource(replacePath);//经过传入这个相对途径就能够找到target下classes下com/hhxy/llb/service
//            System.out.println(resource);
//            System.out.println("----------------------------------------------------------------");
            File file = new File(resource.getFile());//看看拿到target下classes下com/hhxy/llb/service下的文件或目录
            if (file.isDirectory()){//判别拿到的目标file是不是目录
                for (File f : file.listFiles()) {//是一个目录的话就遍历出目录下一切文件
                    String absolutePath = f.getAbsolutePath();
//                    System.out.println(absolutePath);
//                    System.out.println("----------------------------------------------------------------");
                    //需求判别这两个.class文件是否有注解@Component
                    //最简略的办法是用classLoader把这俩个class文件加载再判别
//                    Class<?> aClass = classLoader.loadClass();
//                    if (aClass.isAnnotationPresent(Component.class)) {
//                    }
//spring内部用的是其他办法   ASM技术
                    absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));//截取com最初,.class结尾的途径
                    absolutePath = absolutePath.replace("\\", ".");//把/转换成.
                    System.out.println(absolutePath);
                    try {
                        Class<?> aClass = classLoader.loadClass(absolutePath);//target下classes下com/hhxy/llb/service下的文件运用classLoader加载进来
                        if (aClass.isAnnotationPresent(Component.class)){//判别classloader加载的类是否含有Component
                            //Bean
                            System.out.println(aClass);//能输出的都是bean也便是带了@Component的UserService
                            //可是咱们此刻是需求一个单例bean
                            if (aClass.isAnnotationPresent(Scope.class)) {//判别classloader加载的类是否含有Scope
                                Scope scopeAnnotation = aClass.getAnnotation(Scope.class);//拿到Scope信息
                                String scopeValue = scopeAnnotation.value();//拿到Scope注解中的值
                                //此刻是直接创立bean?
                                //接着看下面的getBean
                            }else {
                                //单例
                            }
                        }
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    //为了完结context.getBean   在容器中获取bean目标
    public Object getBean(String beanName) {
        //beanName---->UserService.class---->再去判别当时类是否含有@Scope注解,注解中内容是什么
        //这样经过beanName来查找UserService.class的话查找注解@Scope内容等重复一遍   较为繁琐
        //所以此刻咱们应该引进一个BeanDefinition
        return null;
    }
}
//com.hhxy.spring下 BeanDefinition
public class BeanDefinition {
    private Class type;//bean的类型
    private String scope;//单例或原型
    private boolean isLazy;//是否是懒加载的
}

增加了BeanDefinition后,咱们在修正一下前面的逻辑

public class LLBApplicationContext {
    //为了完结TestLLBApplicationContext()里边接纳参数
    private Class configClass;//界说一个装备类参数
    private Map<String,BeanDefinition> beanDefinitionMap = new HashMap<String, BeanDefinition>();
    public LLBApplicationContext(Class configClass) {
        this.configClass = configClass;
        scan(configClass);//扫描办法
    }
    //为了完结context.getBean   在容器中获取bean目标
    public Object getBean(String beanName) {
        //beanName---->UserService.class---->再去判别当时类是否含有@Scope注解,注解中内容是什么
        //这样经过beanName来查找UserService.class的话查找注解@Scope内容等重复一遍   较为繁琐
        return null;
    }
    private void scan(Class configClass) {
        if (configClass.isAnnotationPresent(ComponentScan.class)){//先判别该类上是否界说了ComponentScan注解
            //界说了就接纳ComponentScan的信息
            ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            //在从ComponentScan中获取扫描途径
            String path = componentScanAnnotation.value();
            String replacePath = path.replace(".", "/");//com/hhxy/llb/service  相对途径
//            System.out.println(replacePath);
//            System.out.println("----------------------------------------------------------------");
            ClassLoader classLoader = LLBApplicationContext.class.getClassLoader();
            URL resource = classLoader.getResource(replacePath);//经过传入这个相对途径就能够找到target下classes下com/hhxy/llb/service
//            System.out.println(resource);
//            System.out.println("----------------------------------------------------------------");
            File file = new File(resource.getFile());//看看拿到target下classes下com/hhxy/llb/service下的文件或目录
            if (file.isDirectory()){//判别拿到的目标file是不是目录
                for (File f : file.listFiles()) {//是一个目录的话就遍历出目录下一切文件
                    String absolutePath = f.getAbsolutePath();
//                    System.out.println(absolutePath);
//                    System.out.println("----------------------------------------------------------------");
                    //需求判别这两个.class文件是否有注解@Component
                    //最简略的办法是用classLoader把这俩个class文件加载再判别
//                    Class<?> aClass = classLoader.loadClass();
//                    if (aClass.isAnnotationPresent(Component.class)) {
//                    }
//spring内部用的是其他办法   ASM技术
                    absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));//截取com最初,.class结尾的途径
                    absolutePath = absolutePath.replace("\\", ".");//把/转换成.
                    System.out.println(absolutePath);
                    try {
                        Class<?> aClass = classLoader.loadClass(absolutePath);//target下classes下com/hhxy/llb/service下的文件运用classLoader加载进来
                        if (aClass.isAnnotationPresent(Component.class)){//判别classloader加载的类是否含有Component
                            //由于咱们的bean上有Component注解,里边能够自界说姓名,或许默许首字母小写
                            Component componentAnnotation = aClass.getAnnotation(Component.class);//获取Component一切信息
                            String beanName = componentAnnotation.value();//拿到component中的值
                            //Bean
//                            System.out.println(aClass);//能输出的都是bean也便是带了@Component的UserService
                            //可是咱们此刻是需求一个单例bean
                            BeanDefinition beanDefinition = new BeanDefinition();//由于存在component注解,所以就能够为它创立一个BeanDefinition描绘信息
                            beanDefinition.setType(aClass);//界说bean的类型
                            if (aClass.isAnnotationPresent(Scope.class)) {//判别classloader加载的类是否含有Scope
                                Scope scopeAnnotation = aClass.getAnnotation(Scope.class);//拿到Scope信息
                                String scopeValue = scopeAnnotation.value();//拿到Scope注解中的值
                                beanDefinition.setScope(scopeValue);//把Scope的值设置到BeanDefinition bean的描绘中 的Scope中
                            }else {
                                //单例
                                beanDefinition.setScope("singleton");
                            }
                            //把信息存入到map里  键为beanName,值为beanDefinition目标
                            beanDefinitionMap.put(beanName,beanDefinition);
                        }
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

该scan扫描办法做了哪些事情

首要是解析传入进来的类—-》得到扫描途径—-》遍历途径每一个.class文件—-》加载每一个.class文件得到一个class目标—-》判别是否携带Component注解—-》然后去解析bean的姓名beanName—-》解析Scope注解—-》得到beanDefinition目标—-》存到beanDefinitionMap中

//改造LLBApplicationContext中getBean()办法
   //为了完结context.getBean   在容器中获取bean目标
    public Object getBean(String beanName) {
        //beanName---->UserService.class---->再去判别当时类是否含有@Scope注解,注解中内容是什么
        //这样经过beanName来查找UserService.class的话查找注解@Scope内容等重复一遍   较为繁琐
        if(!beanDefinitionMap.containsKey(beanName)) {
            //bean的称号不存在
            throw new NullPointerException();
        }
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition.getScope().equals("singleton")){
            //单例   依照姓名从单例池中查找单例bean
            Object singletonBean = singletonObjects.get(beanName);
            return singletonBean;
        }else {
            //原型bean的完结 每一次get都会从头创立一个bean
            Object prototypeBean = createBean(beanName, beanDefinition);
            return prototypeBean;
        }
    }
//改造LLBApplicationContext中scan()办法
 private void scan(Class configClass) {
        if (configClass.isAnnotationPresent(ComponentScan.class)){//先判别该类上是否界说了ComponentScan注解
            //界说了就接纳ComponentScan的信息
            ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            //在从ComponentScan中获取扫描途径
            String path = componentScanAnnotation.value();
            String replacePath = path.replace(".", "/");//com/hhxy/llb/service  相对途径
//            System.out.println(replacePath);
//            System.out.println("----------------------------------------------------------------");
            ClassLoader classLoader = LLBApplicationContext.class.getClassLoader();
            URL resource = classLoader.getResource(replacePath);//经过传入这个相对途径就能够找到target下classes下com/hhxy/llb/service
//            System.out.println(resource);
//            System.out.println("----------------------------------------------------------------");
            File file = new File(resource.getFile());//看看拿到target下classes下com/hhxy/llb/service下的文件或目录
            if (file.isDirectory()){//判别拿到的目标file是不是目录
                for (File f : file.listFiles()) {//是一个目录的话就遍历出目录下一切文件
                    String absolutePath = f.getAbsolutePath();
//                    System.out.println(absolutePath);
//                    System.out.println("----------------------------------------------------------------");
                    //需求判别这两个.class文件是否有注解@Component
                    //最简略的办法是用classLoader把这俩个class文件加载再判别
//                    Class<?> aClass = classLoader.loadClass();
//                    if (aClass.isAnnotationPresent(Component.class)) {
//                    }
//spring内部用的是其他办法   ASM技术
                    absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));//截取com最初,.class结尾的途径
                    absolutePath = absolutePath.replace("\\", ".");//把/转换成.
//                    System.out.println(absolutePath);
                    try {
                        Class<?> aClass = classLoader.loadClass(absolutePath);//target下classes下com/hhxy/llb/service下的文件运用classLoader加载进来
                        if (aClass.isAnnotationPresent(Component.class)){//判别classloader加载的类是否含有Component
                            //由于咱们的bean上有Component注解,里边能够自界说姓名,或许默许首字母小写
                            Component componentAnnotation = aClass.getAnnotation(Component.class);//获取Component一切信息
                            String beanName = componentAnnotation.value();//拿到component中的值
                            //Bean
//                            System.out.println(aClass);//能输出的都是bean也便是带了@Component的UserService
                            //可是咱们此刻是需求一个单例bean
                            BeanDefinition beanDefinition = new BeanDefinition();//由于存在component注解,所以就能够为它创立一个BeanDefinition描绘信息
                            beanDefinition.setType(aClass);//界说bean的类型
                            if (aClass.isAnnotationPresent(Scope.class)) {//判别classloader加载的类是否含有Scope
                                Scope scopeAnnotation = aClass.getAnnotation(Scope.class);//拿到Scope信息
                                String scopeValue = scopeAnnotation.value();//拿到Scope注解中的值
                                beanDefinition.setScope(scopeValue);//把Scope的值设置到BeanDefinition bean的描绘中 的Scope中
                            }else {
                                //单例
                                beanDefinition.setScope("singleton");
                            }
                            //把信息存入到map里  键为beanName,值为beanDefinition目标
                            beanDefinitionMap.put(beanName,beanDefinition);
                        }
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
//改造LLBApplicationContext中createBean()办法
 private Object createBean(String beanName,BeanDefinition beanDefinition){
        //怎么创立bean
        //肯定是依据bean的类型创立
        Class type = beanDefinition.getType();
        Object instance=null;
        try {
            //经过调用类的无参结构办法实例化得到目标instance
            instance = type.getConstructor().newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return instance;
    }
//改造LLBApplicationContext中变量
//为了完结TestLLBApplicationContext()里边接纳参数
    private Class configClass;//界说一个装备类参数
    private Map<String,BeanDefinition> beanDefinitionMap = new HashMap<String, BeanDefinition>();//bean详细信息
    private Map<String,Object> singletonObjects = new HashMap<String, Object>();//单例池
    public LLBApplicationContext(Class configClass) {
        this.configClass = configClass;
        scan(configClass);//扫描办法
        //创立单例bean
        //遍历map中一切信息  map中存储的是entrySet  entrySet-entry组成
        for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : beanDefinitionMap.entrySet()) {
            String beanName = beanDefinitionEntry.getKey();//获取beanName
            BeanDefinition beanValue = beanDefinitionEntry.getValue();//BeanDefinitionbean的描绘依靠信息
            if (beanValue.getScope().equals("singleton")){ //判别scope是否有值值是否等于singleton
                //找到单例bean   这时分应该创立bean
                Object bean = createBean(beanName, beanValue);
                //把创立的单例bean,寄存到单例池中
                singletonObjects.put(beanName,bean);
            }
        }
    }
//完好的LLBApplicationContext类
public class LLBApplicationContext {
    //为了完结TestLLBApplicationContext()里边接纳参数
    private Class configClass;//界说一个装备类参数
    private Map<String,BeanDefinition> beanDefinitionMap = new HashMap<String, BeanDefinition>();//bean详细信息
    private Map<String,Object> singletonObjects = new HashMap<String, Object>();//单例池
    public LLBApplicationContext(Class configClass) {
        this.configClass = configClass;
        scan(configClass);//扫描办法
        //创立单例bean
        //遍历map中一切信息  map中存储的是entrySet  entrySet-entry组成
        for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : beanDefinitionMap.entrySet()) {
            String beanName = beanDefinitionEntry.getKey();//获取beanName
            BeanDefinition beanValue = beanDefinitionEntry.getValue();//BeanDefinitionbean的描绘依靠信息
            if (beanValue.getScope().equals("singleton")){ //判别scope是否有值值是否等于singleton
                //找到单例bean   这时分应该创立bean
                Object bean = createBean(beanName, beanValue);
                //把创立的单例bean,寄存到单例池中
                singletonObjects.put(beanName,bean);
            }
        }
    }
    private Object createBean(String beanName,BeanDefinition beanDefinition){
        //怎么创立bean
        //肯定是依据bean的类型创立
        Class type = beanDefinition.getType();
        Object instance=null;
        try {
            //经过调用类的无参结构办法实例化得到目标instance
            instance = type.getConstructor().newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return instance;
    }
    //为了完结context.getBean   在容器中获取bean目标
    public Object getBean(String beanName) {
        //beanName---->UserService.class---->再去判别当时类是否含有@Scope注解,注解中内容是什么
        //这样经过beanName来查找UserService.class的话查找注解@Scope内容等重复一遍   较为繁琐
        if(!beanDefinitionMap.containsKey(beanName)) {
            //bean的称号不存在
            throw new NullPointerException();
        }
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition.getScope().equals("singleton")){
            //单例   依照姓名从单例池中查找单例bean
            Object singletonBean = singletonObjects.get(beanName);
            return singletonBean;
        }else {
            //原型bean的完结 每一次get都会从头创立一个bean
            Object prototypeBean = createBean(beanName, beanDefinition);
            return prototypeBean;
        }
    }
    private void scan(Class configClass) {
        if (configClass.isAnnotationPresent(ComponentScan.class)){//先判别该类上是否界说了ComponentScan注解
            //界说了就接纳ComponentScan的信息
            ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            //在从ComponentScan中获取扫描途径
            String path = componentScanAnnotation.value();
            String replacePath = path.replace(".", "/");//com/hhxy/llb/service  相对途径
//            System.out.println(replacePath);
//            System.out.println("----------------------------------------------------------------");
            ClassLoader classLoader = LLBApplicationContext.class.getClassLoader();
            URL resource = classLoader.getResource(replacePath);//经过传入这个相对途径就能够找到target下classes下com/hhxy/llb/service
//            System.out.println(resource);
//            System.out.println("----------------------------------------------------------------");
            File file = new File(resource.getFile());//看看拿到target下classes下com/hhxy/llb/service下的文件或目录
            if (file.isDirectory()){//判别拿到的目标file是不是目录
                for (File f : file.listFiles()) {//是一个目录的话就遍历出目录下一切文件
                    String absolutePath = f.getAbsolutePath();
//                    System.out.println(absolutePath);
//                    System.out.println("----------------------------------------------------------------");
                    //需求判别这两个.class文件是否有注解@Component
                    //最简略的办法是用classLoader把这俩个class文件加载再判别
//                    Class<?> aClass = classLoader.loadClass();
//                    if (aClass.isAnnotationPresent(Component.class)) {
//                    }
//spring内部用的是其他办法   ASM技术
                    absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));//截取com最初,.class结尾的途径
                    absolutePath = absolutePath.replace("\\", ".");//把/转换成.
//                    System.out.println(absolutePath);
                    try {
                        Class<?> aClass = classLoader.loadClass(absolutePath);//target下classes下com/hhxy/llb/service下的文件运用classLoader加载进来
                        if (aClass.isAnnotationPresent(Component.class)){//判别classloader加载的类是否含有Component
                            //由于咱们的bean上有Component注解,里边能够自界说姓名,或许默许首字母小写
                            Component componentAnnotation = aClass.getAnnotation(Component.class);//获取Component一切信息
                            String beanName = componentAnnotation.value();//拿到component中的值
                            //Bean
//                            System.out.println(aClass);//能输出的都是bean也便是带了@Component的UserService
                            //可是咱们此刻是需求一个单例bean
                            BeanDefinition beanDefinition = new BeanDefinition();//由于存在component注解,所以就能够为它创立一个BeanDefinition描绘信息
                            beanDefinition.setType(aClass);//界说bean的类型
                            if (aClass.isAnnotationPresent(Scope.class)) {//判别classloader加载的类是否含有Scope
                                Scope scopeAnnotation = aClass.getAnnotation(Scope.class);//拿到Scope信息
                                String scopeValue = scopeAnnotation.value();//拿到Scope注解中的值
                                beanDefinition.setScope(scopeValue);//把Scope的值设置到BeanDefinition bean的描绘中 的Scope中
                            }else {
                                //单例
                                beanDefinition.setScope("singleton");
                            }
                            //把信息存入到map里  键为beanName,值为beanDefinition目标
                            beanDefinitionMap.put(beanName,beanDefinition);
                        }
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

大致的spring完结 能够完结单例、原型

测验

//test类
public class Test {
    public static void main(String[] args) {
        //仿照
        /**
         * //非懒加载的单例bean
         * AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
         * UserService userService = (UserService)context.getBean("userService");
         * 写法
         */
        LLBApplicationContext context = new LLBApplicationContext(AppConfig.class);
//        UserService userService = (UserService) context.getBean("userService");
//        userService.test();
        //获取多个bean测验看UserService中Scope值为singleton 判别bean是否相同是否为单例bean
        System.out.println((UserService) context.getBean("userService"));
        System.out.println((UserService) context.getBean("userService"));
        System.out.println((UserService) context.getBean("userService"));
    }
}

履行作用如下,UserService是单例目标singleton

com.hhxy.llb.service.UserService@5e2de80c
com.hhxy.llb.service.UserService@5e2de80c
com.hhxy.llb.service.UserService@5e2de80c
//单例创立目标都是同一个

咱们再来去掉UserService上注解@Scope(“singleton”) 再检查履行作用

com.hhxy.llb.service.UserService@60e53b93
com.hhxy.llb.service.UserService@60e53b93
com.hhxy.llb.service.UserService@60e53b93
//默许不写,单例创立目标都是同一个

接着修正UserService上注解为@Scope(“prototype”) 再检查履行作用

com.hhxy.llb.service.UserService@5e2de80c
com.hhxy.llb.service.UserService@1d44bcfa
com.hhxy.llb.service.UserService@266474c2
//原型就每一个目标不同

测验给OrderService加上Component注解

运转test发现

@Component
public class OrderService {
    public void test(){
        System.out.println("test");
    }
}
public class Test {
    public static void main(String[] args) {
        //仿照
        /**
         * //非懒加载的单例bean
         * AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
         * UserService userService = (UserService)context.getBean("userService");
         * 写法
         */
        LLBApplicationContext context = new LLBApplicationContext(AppConfig.class);
//        UserService userService = (UserService) context.getBean("userService");
//        userService.test();
        //获取多个bean测验看UserService中Scope值为singleton 判别bean是否相同是否为单例bean
        System.out.println((UserService) context.getBean("userService"));
        System.out.println((UserService) context.getBean("userService"));
        System.out.println((OrderService) context.getBean("orderService"));
    }
}
com.hhxy.llb.service.UserService@60e53b93
com.hhxy.llb.service.UserService@60e53b93
Exception in thread "main" java.lang.NullPointerException
	at com.hhxy.spring.LLBApplicationContext.getBean(LLBApplicationContext.java:67)
	at com.hhxy.llb.Test.main(Test.java:22)

由于没有给姓名beanName默许就为空了

这个时分咱们检查spring源码能够发现给某个类创立一个姓名办法的代码其实很简略就简略的一句话

//Introspector.decapitalize(aClass.getSimpleName());  
//以下是我在LLBApplicationContext获取@Component注解值时参加的代码
if ("".equals(beanName)){
                                beanName = Introspector.decapitalize(aClass.getSimpleName());
                            }
//测验代码
public class Test {
    public static void main(String[] args) {
        //仿照
        /**
         * //非懒加载的单例bean
         * AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
         * UserService userService = (UserService)context.getBean("userService");
         * 写法
         */
        LLBApplicationContext context = new LLBApplicationContext(AppConfig.class);
//        UserService userService = (UserService) context.getBean("userService");
//        userService.test();
        //获取多个bean测验看UserService中Scope值为singleton 判别bean是否相同是否为单例bean
        System.out.println((UserService) context.getBean("userService"));
        System.out.println((UserService) context.getBean("userService"));
        System.out.println((OrderService) context.getBean("orderService"));
    }
}
//测验成果   这个是OrderService上@Component注解内没有值
com.hhxy.llb.service.UserService@60e53b93
com.hhxy.llb.service.UserService@60e53b93
com.hhxy.llb.service.OrderService@5e2de80c

这时分咱们考虑增加一个@Autowired注解 依靠注入


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)//该注解能够用在字段特点上
//用来给bean创立一个姓名
public @interface Autowired {
}

接着在UserService增加上一段

@Autowired
private OrderService orderService;

再编写Test类改造

        LLBApplicationContext context = new LLBApplicationContext(AppConfig.class);
//        UserService userService = (UserService) context.getBean("userService");
//        userService.test();
        //获取多个bean测验看UserService中Scope值为singleton 判别bean是否相同是否为单例bean
        UserService userService = (UserService) context.getBean("userService");
        userService.test();

这个时分请问userService里的test办法中的orderService是否有值呢

答案是没有为null。。。

要怎么完结依靠注入 —在bean的创立时createBean

//createBean中特点赋值
  private Object createBean(String beanName,BeanDefinition beanDefinition){
        //怎么创立bean
        //肯定是依据bean的类型创立
        Class type = beanDefinition.getType();
        Object instance=null;
        try {
            //经过调用类的无参结构办法实例化得到目标instance
            instance = type.getConstructor().newInstance();
            //这边要是存在一个有参狗办法运用需求传参,参数值是需求经过类型或许姓名来获取
            //依靠注入
            for (Field field : type.getDeclaredFields()) {//遍历出该目标一切特点
                if (field.isAnnotationPresent(Autowired.class)) {//判别哪些特点上存在@Autowired注解
                    field.setAccessible(true);//反射
                    //特点设置值,一个目标  一个依据目标类型去找
                    //field.getType()//界说一个新的map,key为Class,value为beanDefinition   在扫描scan的时分把每一个加载的class与beanDefinition存在map里边去
                    //field.set(instance,????);
                    //给这个特点值赋值,经过这个instance(UserService)目标的字段特点名(field)去赋值
                    //赋什么值,经过这个字段的姓名去调用getBean办法,得到一个bean目标,然后将这个bean赋值给这个字段
                    field.set(instance,getBean(field.getName()));//或许存在循环依靠问题
                }
            }
//假如首要创立得bean是UserService,在特点赋值时经过orderService姓名去找bean,发现bean没有该怎样办呢?
//在getBean办法中回来单例目标
public Object getBean(String beanName) {
        //beanName---->UserService.class---->再去判别当时类是否含有@Scope注解,注解中内容是什么
        //这样经过beanName来查找UserService.class的话查找注解@Scope内容等重复一遍   较为繁琐
        if(!beanDefinitionMap.containsKey(beanName)) {
            //bean的称号不存在
            throw new NullPointerException();
        }
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition.getScope().equals("singleton")){
            //单例   依照姓名从单例池中查找单例bean
            Object singletonBean = singletonObjects.get(beanName);
            if (singletonBean==null){//假如UserService先创立,给特点赋值,而OrderService并没有创立  那就只能再创立一个值
                singletonBean = createBean(beanName,beanDefinition);
                singletonObjects.put(beanName,singletonBean);
            }
            return singletonBean;
        }else {
            //原型bean的完结 每一次get都会从头创立一个bean
            Object prototypeBean = createBean(beanName, beanDefinition);
            return prototypeBean;
        }
    }

接着再次测验Test.class

        LLBApplicationContext context = new LLBApplicationContext(AppConfig.class);
//        UserService userService = (UserService) context.getBean("userService");
//        userService.test();
        //获取多个bean测验看UserService中Scope值为singleton 判别bean是否相同是否为单例bean
        UserService userService = (UserService) context.getBean("userService");
        userService.test();

console输出

com.hhxy.llb.service.OrderService@6f94fa3e

接下来仿照初始化操作 spring里有接口InitializingBean

//接口InitializingBean
//内部办法 spring内源码办法
void afterPropertiesSet(); 
//UserService完结这个接口 重写该办法
@Component("userService")
//@Scope("singleton")
//@Scope("prototype")
public class UserService implements InitializingBean {
    //给这个OrderService赋值,最开端能够依照类型来找  从单例池里去寻觅  可是orderService或许在单例池没有找到,由于orderService目标还没有创立,这个时分就能够依靠BeanDefinition中特点了Class 依据某一个类型来找到该类型bean到底有几个有哪些
    //依据类型去寻觅bean假如找到多个就能够依据姓名去找,依据姓名就能够看咱们写的LLBApplicationContext这个类两个map都寄存的是beanName,既能够去单例池中去找,也能够去BeanDefinition中去找
    //这就相似byType,byName
    @Autowired
    private OrderService orderService;
    public void test(){
        System.out.println(orderService);
    }
    @Override
    public void afterPropertiesSet() {
        System.out.println("初始化");
    }
}

这个重写的办法暂时现在还调用不到,还没有完善

应该在创立某一个bean的进程中间 依靠注入过后,spring支持这个功用

//创立bean  ---createBean
 private Object createBean(String beanName,BeanDefinition beanDefinition){
        //怎么创立bean
        //肯定是依据bean的类型创立
        Class type = beanDefinition.getType();
        Object instance=null;
        try {
            //经过调用类的无参结构办法实例化得到目标instance
            instance = type.getConstructor().newInstance();
            //这边要是存在一个有参狗办法运用需求传参,参数值是需求经过类型或许姓名来获取
            //依靠注入
            for (Field field : type.getDeclaredFields()) {//遍历出该目标一切特点
                if (field.isAnnotationPresent(Autowired.class)) {//判别哪些特点上存在@Autowired注解
                    field.setAccessible(true);//反射
                    //特点设置值,一个目标  一个依据目标类型去找
                    //field.getType()//界说一个新的map,key为Class,value为beanDefinition   在扫描scan的时分把每一个加载的class与beanDefinition存在map里边去
                    //field.set(instance,????);
                    //给这个特点值赋值,经过这个instance(UserService)目标的字段特点名(field)去赋值
                    //赋什么值,经过这个字段的姓名去调用getBean办法,得到一个bean目标,然后将这个bean赋值给这个字段
                    field.set(instance,getBean(field.getName()));//或许存在循环依靠问题
                }
            }
            //在恣意的bean中完结这个接口,spring就会主动帮咱们调用这个办法
            if (instance instanceof InitializingBean){//判别这个目标是否完结了InitializingBean这个接口
                ((InitializingBean)instance).afterPropertiesSet();//然后把这个目标转换成InitializingBean目标调用这个办法
            }

运转Test.class test没有做修正,成果如下

初始化
com.hhxy.llb.service.OrderService@6f94fa3e

要点讲解BeanPostProcesor 初始化前后都跟这个接口息息相关

检查spring源码BeanPostProcesor 能够发现两个办法

@NotNull
default Object postProcessBeforeInterInitialization(Object bean,String beanName) throw BeansException{
    return bean;
}
@NotNull
default Object postProcessAfterInterInitialization(Object bean,String beanName) throw BeansException{
    return bean;
}

界说好接口BeanPostProcesor

public interface BeanPostProcesor {
    default Object postProcessBeforeInterInitialization(Object bean,String beanName) {
        return bean;
    }
    default Object postProcessAfterInterInitialization(Object bean,String beanName){
      return bean;
    }
}

再界说一个类用来完结该办法能够再办法内部写恣意逻辑


public class LLBBeanPostProcessor implements BeanPostProcesor {
    @Override
    public Object postProcessBeforeInterInitialization(Object bean, String beanName) {
        return null;
    }
    @Override
    public Object postProcessAfterInterInitialization(Object bean, String beanName) {
        return null;
    }
}

接着咱们能够在创立bean初始化时那个当地进行初始化前,初始化后等操作

以下代码是我个人思路见地


    private Object createBean(String beanName,BeanDefinition beanDefinition){
        //怎么创立bean
        //肯定是依据bean的类型创立
        Class type = beanDefinition.getType();
        Object instance=null;
        try {
            //经过调用类的无参结构办法实例化得到目标instance
            instance = type.getConstructor().newInstance();
            //这边要是存在一个有参狗办法运用需求传参,参数值是需求经过类型或许姓名来获取
            //依靠注入
            for (Field field : type.getDeclaredFields()) {//遍历出该目标一切特点
                if (field.isAnnotationPresent(Autowired.class)) {//判别哪些特点上存在@Autowired注解
                    field.setAccessible(true);//反射
                    //特点设置值,一个目标  一个依据目标类型去找
                    //field.getType()//界说一个新的map,key为Class,value为beanDefinition   在扫描scan的时分把每一个加载的class与beanDefinition存在map里边去
                    //field.set(instance,????);
                    //给这个特点值赋值,经过这个instance(UserService)目标的字段特点名(field)去赋值
                    //赋什么值,经过这个字段的姓名去调用getBean办法,得到一个bean目标,然后将这个bean赋值给这个字段
                    field.set(instance,getBean(field.getName()));//或许存在循环依靠问题
                }
            }
            //初始化前
            LLBBeanPostProcessor llbBeanPostProcessor = new LLBBeanPostProcessor();
            llbBeanPostProcessor.postProcessBeforeInterInitialization(instance,beanName);
            //在恣意的bean中完结这个接口,spring就会主动帮咱们调用这个办法
            if (instance instanceof InitializingBean){//判别这个目标是否完结了InitializingBean这个接口
                ((InitializingBean)instance).afterPropertiesSet();//然后把这个目标转换成InitializingBean目标调用这个办法
            }
            //初始化后
            llbBeanPostProcessor.postProcessAfterInterInitialization(instance,beanName);
            //以上初始化前后就会调用LLBBeanPostProcessor里的两个初始化前后办法,能够进行业务逻辑编写
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return instance;
    }

能够发现假如直接实例化自己写的那个类,spring内部会这样写么,肯定不会,是运用接口获取实例

那么咱们得先让spring知道这个类,所以咱们能够在LLBBeanPostProcessor类上增加一个@Component注解

@Component
public class LLBBeanPostProcessor implements BeanPostProcesor {
    @Override
    public Object postProcessBeforeInterInitialization(Object bean, String beanName) {
        System.out.println(beanName);
        return bean;
    }
    @Override
    public Object postProcessAfterInterInitialization(Object bean, String beanName) {
        System.out.println(beanName);
        return bean;
    }

所以咱们在扫描的时分依据加了@Component注解的类进行判别,判别是否完结了BeanPostProcesor接口

//创立了一个list用于存储BeanPostProcesor
 private List<BeanPostProcesor> beanPostProcesorsList = new ArrayList<BeanPostProcesor>();
if (aClass.isAnnotationPresent(Component.class)){//判别classloader加载的类是否含有Component
                            if (BeanPostProcesor.class.isAssignableFrom(aClass)) {//判别该类是否完结了BeanPostProcesor
                                //instanceof某一个目标类型,这儿是某一个类
                                BeanPostProcesor instance = (BeanPostProcesor) aClass.getConstructor().newInstance();
                                //每拿到一个BeanPostProcesor目标就放到beanPostProcesorsList里
                                beanPostProcesorsList.add(instance);
                            }

再接着从创立bean时,初始化后边增加

//            //初始化后
//            llbBeanPostProcessor.postProcessAfterInterInitialization(instance,beanName);
            for (BeanPostProcesor beanPostProcesor : beanPostProcesorsList) {//遍历一切BeanPostProcesor
                //把实例目标传给你再调用该办法再把这个办法的办法回来值目标又赋值给它
                instance = beanPostProcesor.postProcessAfterInterInitialization(instance,beanName);//调用xx目标调用办法 一旦调用这个办法instance就变成回来的一个署理目标了  就会创立一个userService的署理目标
            }

这样能够完结aop

aop底层也是依据BeanPostProcesor来做的

//增加接口完善动态署理
public interface UserInterface {
    public void test();
}

在UserService里边去完结这个接口

@Component("userService")
//@Scope("singleton")
//@Scope("prototype")
public class UserService implements UserInterface ,InitializingBean {
    //给这个OrderService赋值,最开端能够依照类型来找  从单例池里去寻觅  可是orderService或许在单例池没有找到,由于orderService目标还没有创立,这个时分就能够依靠BeanDefinition中特点了Class 依据某一个类型来找到该类型bean到底有几个有哪些
    //依据类型去寻觅bean假如找到多个就能够依据姓名去找,依据姓名就能够看咱们写的LLBApplicationContext这个类两个map都寄存的是beanName,既能够去单例池中去找,也能够去BeanDefinition中去找
    //这就相似byType,byName
    @Autowired
    private OrderService orderService;
    @Override
    public void afterPropertiesSet() {
        System.out.println("初始化");
    }
    public void test(){
        System.out.println(orderService);
    }
}

能够在LLBBeanPostProcessor的postProcessAfterInterInitialization界说自己写的东西 不过得先仿照出jdk动态署理

  @Override
    public Object postProcessAfterInterInitialization(Object bean, String beanName) {
        if (beanName.equals("userService")){
            //最好是运用cglib方式  完结aop
            //做一下简略完结
            //生成一个署理目标   仿照jdk动态署理
            Object proxyInstance = Proxy.newProxyInstance(LLBBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
                @Override            //署理目标
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //test类进行调用进入到这个办法中
                    //界说切面逻辑
                    System.out.println("切面逻辑");
                    return method.invoke(bean,args);//终究仍是要履行原始的bean(userService)目标办法
                }
            });
            return proxyInstance;
        }
        return bean;
    }

这样当创立bean时调用下面这行代码时就会回来一个署理目标

instance = beanPostProcesor.postProcessAfterInterInitialization(instance,beanName);//调用xx目标调用办法 一旦调用这个办法instance就变成回来的一个署理目标了  就会创立一个userService的署理目标

这个署理目标里就界说了切面逻辑,然后终究仍是得履行原始的bean(UserService)目标办法

Test进行测验

public class Test {
    public static void main(String[] args) {
        //仿照
        /**
         * //非懒加载的单例bean
         * AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
         * UserService userService = (UserService)context.getBean("userService");
         * 写法
         */
        LLBApplicationContext context = new LLBApplicationContext(AppConfig.class);
//        UserService userService = (UserService) context.getBean("userService");
//        userService.test();
        //获取多个bean测验看UserService中Scope值为singleton 判别bean是否相同是否为单例bean
        UserInterface userService = (UserInterface) context.getBean("userService");
        userService.test();
    }
}
//履行成果如下
初始化
切面逻辑
com.hhxy.llb.service.OrderService@63947c6b

这样大致的aop功用不久完结了么

依据BeanPostProcessor这个机制能够对bean做出很多种事情

现在假设我想完结一个功用,自界说一个注解@LLBValue 经过自界说注解把注解中的值写入到下面特点这个name里边

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface LLBValue {
    String value() default "";
}

以及改造UserService


@Component("userService")
//@Scope("singleton")
//@Scope("prototype")
public class UserService implements UserInterface ,InitializingBean {
    //给这个OrderService赋值,最开端能够依照类型来找  从单例池里去寻觅  可是orderService或许在单例池没有找到,由于orderService目标还没有创立,这个时分就能够依靠BeanDefinition中特点了Class 依据某一个类型来找到该类型bean到底有几个有哪些
    //依据类型去寻觅bean假如找到多个就能够依据姓名去找,依据姓名就能够看咱们写的LLBApplicationContext这个类两个map都寄存的是beanName,既能够去单例池中去找,也能够去BeanDefinition中去找
    //这就相似byType,byName
    @Autowired
    private OrderService orderService;
    @LLBValue("giao")//经过自界说注解把注解中的值写入到下面特点这个name里边
    private String name;
    @Override
    public void afterPropertiesSet() {
        System.out.println("初始化");
    }
    public void test(){
        System.out.println(name);
        System.out.println(orderService);
    }
}
//在创立bean初始化之前增加
        for (BeanPostProcesor beanPostProcesor : beanPostProcesorsList) {//遍历一切BeanPostProcesor
                beanPostProcesor.postProcessBeforeInterInitialization(instance,beanName);//调用办法
            }
//内部办法
public class LLBBeanValuePostProcessor implements BeanPostProcesor {
    //aop底层便是依据BeanPostProcessor完结的
    @Override
    public Object postProcessBeforeInterInitialization(Object bean, String beanName) {
        System.out.println(beanName);
        return bean;
    }
    @Override
    public Object postProcessAfterInterInitialization(Object bean, String beanName) {
        for (Field f : bean.getClass().getDeclaredFields()) {
            if (f.isAnnotationPresent(LLBValue.class)) {
                f.setAccessible(true);
                try {
                    f.set(bean,f.getAnnotation(LLBValue.class).value());
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return bean;
    }
}

spring中AWare

spring中BeanNameAWare接口

我想知道UserService中的name特点知道自己的bean姓名


@Component("userService")
//@Scope("singleton")
//@Scope("prototype")
public class UserService implements UserInterface ,InitializingBean ,BeanNameAware{
    //给这个OrderService赋值,最开端能够依照类型来找  从单例池里去寻觅  可是orderService或许在单例池没有找到,由于orderService目标还没有创立,这个时分就能够依靠BeanDefinition中特点了Class 依据某一个类型来找到该类型bean到底有几个有哪些
    //依据类型去寻觅bean假如找到多个就能够依据姓名去找,依据姓名就能够看咱们写的LLBApplicationContext这个类两个map都寄存的是beanName,既能够去单例池中去找,也能够去BeanDefinition中去找
    //这就相似byType,byName
    @Autowired
    private OrderService orderService;
    @LLBValue("giao")
    private String giao;
    private String name;
    @Override
    public void afterPropertiesSet() {
        System.out.println("初始化");
    }
    public void test(){
        System.out.println(giao);
        System.out.println(name);
        System.out.println(orderService);
    }
    @Override
    public void setBeanName(String name) {
        this.name = name;
    }
}
 //aware它是在依靠注入完之后,在这个阶段后履行的beanNameAware 再去履行初始化前
//在LLBApplicationContext时改造
          //aware它是在依靠注入完之后,在这个阶段后履行的beanNameAware 再去履行初始化前
            if (instance instanceof BeanNameAware) {
                ((BeanNameAware)instance).setBeanName(beanName);
            }

这样打印的beanName就有值了

           }
        }
    }
    return bean;
}

}


spring中AWare
spring中BeanNameAWare接口
我想知道UserService中的name特点知道自己的bean姓名
```java
@Component("userService")
//@Scope("singleton")
//@Scope("prototype")
public class UserService implements UserInterface ,InitializingBean ,BeanNameAware{
    //给这个OrderService赋值,最开端能够依照类型来找  从单例池里去寻觅  可是orderService或许在单例池没有找到,由于orderService目标还没有创立,这个时分就能够依靠BeanDefinition中特点了Class 依据某一个类型来找到该类型bean到底有几个有哪些
    //依据类型去寻觅bean假如找到多个就能够依据姓名去找,依据姓名就能够看咱们写的LLBApplicationContext这个类两个map都寄存的是beanName,既能够去单例池中去找,也能够去BeanDefinition中去找
    //这就相似byType,byName
    @Autowired
    private OrderService orderService;
    @LLBValue("giao")
    private String giao;
    private String name;
    @Override
    public void afterPropertiesSet() {
        System.out.println("初始化");
    }
    public void test(){
        System.out.println(giao);
        System.out.println(name);
        System.out.println(orderService);
    }
    @Override
    public void setBeanName(String name) {
        this.name = name;
    }
}
 //aware它是在依靠注入完之后,在这个阶段后履行的beanNameAware 再去履行初始化前
//在LLBApplicationContext时改造
          //aware它是在依靠注入完之后,在这个阶段后履行的beanNameAware 再去履行初始化前
            if (instance instanceof BeanNameAware) {
                ((BeanNameAware)instance).setBeanName(beanName);
            }

这样打印的beanName就有值了