一:创建容器骨架(逐步完善容器类)
package com.zhw.spring;
import java.io.File;
import java.lang.annotation.Annotation;
import java.net.URL;
public class ClassPathApplication {
private Class AppConfig;
public ClassPathApplication(Class appConfig) throws Exception {
AppConfig = appConfig;
}
public Object getBean(String beanName) {
return null;
}
}
二:定义@component、@componentScann、@Scope注解
1,@component注解,标记该类的实例需要被Spring容器管理
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
String value() default "";
}
2,@componentScann注解,指定扫描器扫描的范围;只有在Spring的扫描器的扫描范围之内并且有@component、@Service、@Repository等标记类才会被扫描到并且Spring管理该类的实例
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScann {
String value() default "";
}
3,@Scope注解,标记在需要被Spring容器管理的类的上面,指定该类在创建对象时是创建单例的的还是原型的
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Scope {
String value();
}
三:扫描需要容器管理实例的类
1,配置类,@component注解标记了扫描的范围
package com.zhw.config;
import com.zhw.spring.ComponentScann;
@ComponentScann("com.zhw.service")
public class AppConfig {
}
2,完善容器类ClassPathApplication,准确扫描到需要被容器管理的类
package com.zhw.spring;
import java.io.File;
import java.lang.annotation.Annotation;
import java.net.URL;
public class ClassPathApplication {
private Class AppConfig;
public ClassPathApplication(Class appConfig) throws Exception {
AppConfig = appConfig;
// 扫描AppConfig配置类指定的扫描范围
scanner(appConfig);
}
private void scanner(Class appConfig) throws ClassNotFoundException {
ComponentScann componentScannAnnotation = (ComponentScann)appConfig.getDeclaredAnnotation(ComponentScann.class);
// value是需要扫描的范围
String value = componentScannAnnotation.value();
// 由于在磁盘中都是以文件的形式存贮
String path = value.replace('.', '/');
// 该path下所有资源
ClassLoader classLoader = ClassPathApplication.class.getClassLoader();
URL resource = classLoader.getResource(path);
File file = new File(resource.getFile());
// 判断该文件是否为文件夹
if (file.isDirectory()) {
// 该文件夹下所有文件
File[] files = file.listFiles();
for (File file1 : files) {
// 绝对路径
String absolutePath = file1.getAbsolutePath();
// 判断是否是.java编译之后的.class文件
if(absolutePath.endsWith(".class")){
String classNamePre = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
// 类的全限定名
String className = classNamePre.replace('\\', '.');
Class<?> aClass = classLoader.loadClass(className);
Component componentAnnotation = aClass.getDeclaredAnnotation(Component.class);
if(componentAnnotation.value().length()>0){
// className ->该类的实例应该被加入容器
}
}
}
}
}
public Object getBean(String beanName) {
return null;
}
}
四:根据类的作用域(Scope),创建实例;BeanDefinition类的使用
1,创建BeanDefinition类定义Bean
package com.zhw.spring;
public class BeanDefinition {
private Class aClass;
private String scope;
public Class getaClass() {
return aClass;
}
public void setaClass(Class aClass) {
this.aClass = aClass;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
}
2,完善容器类ClassPathApplication,根据作用域创建实例并加入容器
package com.zhw.spring;
import java.io.File;
import java.net.URL;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class ClassPathApplication {
private Class AppConfig;
// 存放所有 BeanDefinition 对象的map
Map<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
// 单例池
Map<String,Object> singletonMap = new ConcurrentHashMap<>();
public ClassPathApplication(Class appConfig) throws Exception {
AppConfig = appConfig;
// 扫描AppConfig配置类指定的扫描范围
scanner(appConfig);
// 经过扫描之后,所有需要创建对象的类的信息都在 beanDefinitionMap 中
Set<Map.Entry<String, BeanDefinition>> beanDefinitionEntrySets = beanDefinitionMap.entrySet();
for (Map.Entry<String, BeanDefinition> beanDefinitionEntrySet : beanDefinitionEntrySets) {
String className = beanDefinitionEntrySet.getKey();
BeanDefinition beanDefinition = beanDefinitionEntrySet.getValue();
if ("singleton".equals(beanDefinition.getScope())){
// 创建该类的对象并放入单例池中
Object bean = createBean(beanDefinition);
singletonMap.put(className,bean);
}
}
}
private void scanner(Class appConfig) throws ClassNotFoundException {
ComponentScann componentScannAnnotation = (ComponentScann)appConfig.getDeclaredAnnotation(ComponentScann.class);
// value是需要扫描的范围
String value = componentScannAnnotation.value();
// 由于在磁盘中都是以文件的形式存贮
String path = value.replace('.', '/');
// 该path下所有资源
ClassLoader classLoader = ClassPathApplication.class.getClassLoader();
URL resource = classLoader.getResource(path);
File file = new File(resource.getFile());
// 判断该文件是否为文件夹
if (file.isDirectory()) {
// 该文件夹下所有文件
File[] files = file.listFiles();
for (File file1 : files) {
// 绝对路径
String absolutePath = file1.getAbsolutePath();
// 判断是否是.java编译之后的.class文件
if(absolutePath.endsWith(".class")){
String classNamePre = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
// 类的全限定名
String className = classNamePre.replace('\\', '.');
Class<?> aClass = classLoader.loadClass(className);
Component componentAnnotation = aClass.getDeclaredAnnotation(Component.class);
if(componentAnnotation.value().length()>0){
// className ->该类的实例应该被加入容器
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setaClass(aClass);
if(aClass.isAnnotationPresent(Scope.class)){
String value1 = aClass.getDeclaredAnnotation(Scope.class).value();
beanDefinition.setScope(value1);
} else {
// 没有标注@Scope注解,就是默认的单例
beanDefinition.setScope("singleton");
}
beanDefinitionMap.put(className,beanDefinition);
}
}
}
}
}
// 创建实例的方法
private Object createBean(BeanDefinition beanDefinition) throws InstantiationException, IllegalAccessException {
Object object = beanDefinition.getaClass().newInstance();
return object;
}
public Object getBean(String beanName) throws InstantiationException, IllegalAccessException {
Object object = null;
// 判断 beanName 是否被扫描到
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if(beanDefinition!=null){
if("singleton".equals(beanDefinition.getScope())){
return singletonMap.get(beanName);
}else{
object = beanDefinition.getaClass().newInstance();
}
}
return object;
}
}
3,测试
3.1 测试(单例)
package com.zhw.service;
import com.zhw.spring.Component;
@Component(value = "quazrtService")
public class QuazrtService {
}
测试
package com.zhw.test;
import com.zhw.config.AppConfig;
import com.zhw.spring.ClassPathApplication;
import com.zhw.spring.ZhanghwApplicationContext;
public class ZhanghwApplicationContextTest {
public static void main(String[] args) throws Exception {
ClassPathApplication classPathApplication = new ClassPathApplication(AppConfig.class);
Object object1 = classPathApplication.getBean("com.zhw.service.QuazrtService");
Object object2 = classPathApplication.getBean("com.zhw.service.QuazrtService");
Object object3 = classPathApplication.getBean("com.zhw.service.QuazrtService");
Object object4 = classPathApplication.getBean("com.zhw.service.QuazrtService");
System.out.println(object1);
System.out.println(object2);
System.out.println(object3);
System.out.println(object4);
}
}
结果
"C:\Program Files\Java\jdk1.8.0_172\bin\java.exe" "-javaagent:D:\IntelliJ IDEA spring\target\classes" com.zhw.test.ZhanghwApplicationContextTest
com.zhw.service.QuazrtService@5e2de80c
com.zhw.service.QuazrtService@5e2de80c
com.zhw.service.QuazrtService@5e2de80c
com.zhw.service.QuazrtService@5e2de80c
Process finished with exit code 0
3.2 测试(prototype原型)
package com.zhw.service;
import com.zhw.spring.Component;
import com.zhw.spring.Scope;
@Component(value = "quazrtService")
@Scope(value = "prototype")
public class QuazrtService {
}
结果
"C:\Program Files\Java\jdk1.8.0_172\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2021.1.3\lib\idea_rt.jar=10780:D:\IntelliJ IDEA 2021.1.3\bin" -
com.zhw.service.QuazrtService@1d44bcfa
com.zhw.service.QuazrtService@266474c2
com.zhw.service.QuazrtService@6f94fa3e
com.zhw.service.QuazrtService@5e481248
Process finished with exit code 0