准备:创建一个空的maven项目
//IOC的加载(启动容器)
ApplicationContext applicationContext = new ApplicationContext(AppConfig.class);
1 容器加载时如何 判断所扫描到的类 上含有Component注解
1.根据传入的配置类拿到ComponentScan类信息
2.获取扫描路径包 com.tes.service--->需转为com/tes/service
3.根据获取到的扫描路径获取在路径包下所有类的信息
4.判断所扫描到的类上是否有Component注解,有的话表示当前类是一个Bean对象
......
1.1 @Component
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
String value() default "";
//默认值为空,可以不写
}
1.2 @ComponentScan
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
//String value() default "";
//扫描路径默认值为空
String value();
}
1.3 AppConfig 配置类
@ComponentScan("com.tes.service")
public class AppConfig {}
1.4 UserService
import com.spring.Component;
import com.spring.Scope;
@Component("userService")
public class UserService {}
1.5 扫描逻辑代码
package com.spring;
import java.io.File;
import java.lang.annotation.Annotation;
import java.net.URL;
public class ApplicationContext {
private Class configClass;
public ApplicationContext(Class configClass) {
this.configClass = configClass;
/*1.根据传入的配置类拿到ComponentScan注解信息
2.获取扫描路径包 com.tes.service--->需转为com/tes/service
3.根据获取到的扫描路径获取在路径包下所有类的信息
4.判断所扫描到的类上是否有Component注解,有的话表示当前类是一个Bean对象
......
* *///解析配置类//ComponentScan注解--->拿到扫描路径--->扫描///在类上是否有注解
//1.
ComponentScan componentScanAnnotation
= (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
//2.
String path = componentScanAnnotation.value();
//获取注解得到的值是否为扫描路径
System.out.println("扫描获取的路径(包): "+path);
//com.tes.service怎么根据包名得到报下面的所有类类加载器
path=path.replace(".", "/");
//--->转换为com/tes/service
System.out.println("转换后的路径(包): "+path);
//扫描
/*类加载器
*App--->classpath
* */
ClassLoader classLoader = ApplicationContext.class.getClassLoader();
//
//通过类加载器获取某一资源
//3.
URL resource = classLoader.getResource(path);
//相对路径
File file = new File(resource.getFile());
if (file.isDirectory()) {//是否为文件
File[] files = file.listFiles();
for (File f : files) {
System.out.println("获取结果绝对路径: "+"\n"+f);
String fileName = f.getAbsolutePath();
if (fileName.endsWith(".class")) {//是class文件才去下一步解析
String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
className = className.replace("\\", ".");
//
System.out.println("提取后: "+className);
/*将得到的D:\project3\2109\spring_origin\target\classes\com\tes\service\UserService.class
* 转化为com.tes.service.UserService
* */
//Class> aClass = classLoader.loadClass("..");
try {
//Class> clazz = classLoader.loadClass("com.tes.service.UserService");
//根据名字加载类,得到calss对象
Class> clazz = classLoader.loadClass(className);
//4.扫描这个类上是否有Component注解
if (clazz.isAnnotationPresent(Component.class)) {
//判断所扫描到的类上是否有Component注解,有的话表示当前类是一个Bean
//...
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}}
}
}}public Object getBean(String beanName){
return null;
}
}
1.6 测试类
public static void main(String[] args) {
ApplicationContext applicationContext = new ApplicationContext(AppConfig.class);
System.out.println(applicationContext.getBean("userService"));
//System.out.println(applicationContext.getBean("userService"));
//System.out.println(applicationContext.getBean("userService"));
}
文章图片
文章图片
2 根据Scope(单例Bean,多例)创建对象 如何拿到beanName
2.1 @Scope
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
String value();
}
2.2 BeanDefinition 【Spring源码逻辑|Spring01 -- 启动和扫描逻辑模拟】bean的定义,当前类型,作用域
package com.spring;
public class BeanDefinition {
private Class clazz;
//当前bean的类型
private String scope;
public Class getClazz() {
return clazz;
}public void setClazz(Class clazz) {
this.clazz = clazz;
}public String getScope() {
return scope;
}public void setScope(String scope) {
this.scope = scope;
}
}
2.3 3 ApplicationContext
package com.spring;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ApplicationContext {
private Class configClass;
private ConcurrentHashMap,Object> singletonObjects=new ConcurrentHashMap<>();
//单例池
private ConcurrentHashMap,BeanDefinition> beanDefinitionMap=new ConcurrentHashMap<>();
public ApplicationContext(Class configClass) {
this.configClass = configClass;
/*1.根据传入的配置类拿到ComponentScan注解信息
2.获取扫描路径包 com.tes.service--->需转为com/tes/service
3.根据获取到的扫描路径获取在路径包下所有类的信息
4.判断所扫描到的类上是否有Component注解,有的话表示当前类是一个Bean对象
......
* *///解析配置类//ComponentScan注解--->拿到扫描路径--->扫描--->BeanDefinition--->BeanDefinitionMap///在类上是否有注解
//1.
scan(configClass);
for (Map.Entry,BeanDefinition> entry : beanDefinitionMap.entrySet()) {
String beanName = entry.getKey();
BeanDefinition beanDefinition = entry.getValue();
if (beanDefinition.getScope().equals("singleton")){
Object bean = createBean(beanDefinition);
//
singletonObjects.put(beanName,bean);
}
}}
public Object createBean(BeanDefinition beanDefinition){
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;
}private void scan(Class configClass) {
ComponentScan componentScanAnnotation
= (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
//2.
String path = componentScanAnnotation.value();
//获取注解得到的值是否为扫描路径
System.out.println("扫描获取的路径(包): "+path);
//com.tes.service怎么根据包名得到报下面的所有类类加载器
path=path.replace(".", "/");
//--->转换为com/tes/service
System.out.println("转换后的路径(包): "+path);
//扫描
/*类加载器
*App--->classpath
* */
ClassLoader classLoader = ApplicationContext.class.getClassLoader();
//
//通过类加载器获取某一资源
//3.
URL resource = classLoader.getResource(path);
//相对路径
File file = new File(resource.getFile());
if (file.isDirectory()) {//是否为文件
File[] files = file.listFiles();
for (File f : files) {
System.out.println("获取结果绝对路径: "+"\n"+f);
String fileName = f.getAbsolutePath();
if (fileName.endsWith(".class")) {//是class文件才去下一步解析
String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
className = className.replace("\\", ".");
//
System.out.println("提取后: "+className);
/*将得到的D:\project3\2109\spring_origin\target\classes\com\tes\service\UserService.class
* 转化为com.tes.service.UserService
* */
//Class> aClass = classLoader.loadClass("..");
try {
//Class> clazz = classLoader.loadClass("com.tes.service.UserService");
//根据名字加载类,得到calss对象
Class> clazz = classLoader.loadClass(className);
//4.扫描这个类上是否有Component注解
if (clazz.isAnnotationPresent(Component.class)) {
//判断所扫描到的类上是否有Component注解,有的话表示当前类是一个Bean
//...
//解析类-->BeanDefinitionComponent componentAnnotation=clazz.getDeclaredAnnotation(Component.class);
String beanName = componentAnnotation.value();
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setClazz(clazz);
if (clazz.isAnnotationPresent(Scope.class)){
Scope scopeAnnotation=clazz.getDeclaredAnnotation(Scope.class);
beanDefinition.setScope(scopeAnnotation.value());
}else{
beanDefinition.setScope("singleton");
}
beanDefinitionMap.put(beanName, beanDefinition);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}}
}
}
}public Object getBean(String beanName){
if (beanDefinitionMap.containsKey(beanName)){
BeanDefinition beanDefinition=beanDefinitionMap.get(beanName);
if (beanDefinition.getScope().equals("singleton")){
Object o = singletonObjects.get(beanName);
return o;
}else {
//创建Bean
Object bean = createBean(beanDefinition);
return bean;
}
}else {
//不存在Bean
throw new NullPointerException();
}
// return null;
}
}
推荐阅读
- JAVA基础|Lambda从入门到精通(一篇搞懂)
- Java学习日记|Java学习日记14——Lambda表达式以及一些高级语法
- android|初学Android网络封装
- rabbitmq|初学rabbitmq总结
- java|java实现文件切片上传百度云+断点续传
- 面试|HashMap常问的11个面试题 你会几个
- 多线程|【java】 如何自己写一把多线程锁 中 重写lock,trylock,unlok方法
- 蓝桥杯|蓝桥杯AcWing学习笔记 4-3排序的学习(附相关蓝桥真题(小朋友排队)(Java))
- #|蓝桥杯31天冲刺打卡题解(Day10)