一、包扫描和创建单例bean案例
public class BeanDefinition {
private Class clazz;
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;
}
}
- ?创建applicationContext对象 处理包扫描以及创建单例Bean的主要功能
package com.example.spring.demo.spring;
import com.example.spring.demo.test.service.UserService;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class cjwApplicationContext {
private Class configClass;
// 单例池
private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, BeanDefinition> beanDefiniationMap = new ConcurrentHashMap<>();//bean的定义
public cjwApplicationContext(Class configClass) throws ClassNotFoundException {
this.configClass = configClass;
//解析配置类
//ComponentScan注解------》扫描路径-----》扫描具体事情---->Beandefinition--->BeanDefinitionMap
//对spring而言对当前传递的类是否有spring的相应注解
scan(configClass);
for (Map.Entry<String, BeanDefinition> entry : beanDefiniationMap.entrySet()) {
String beanName = entry.getKey();
BeanDefinition beanDefinition = beanDefiniationMap.get(beanName);
if (beanDefinition.getScope().equals("singleton")) {
Object bean = createBean(beanDefinition);//单列Bean
singletonObjects.put(beanName, bean);
}
}
}
/**
* 创建单例bean
* @param beanDefinition
* @return
*/
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;
}
//Refactor--->Extact--->Field
private void scan(Class configClass) throws ClassNotFoundException {
ComponentScan cs = (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
String path = cs.value();//扫描路径
System.out.println("path = " + path);
path = path.replace(".", "/");
/**
* 扫描路径 找到ComponentScan注解的类
根据包名得到类 类加载器
1、bootstrap --->jre/lib
2、ext --->jre/ext/lib
3、app --->classpath
*/
ClassLoader classLoader = cjwApplicationContext.class.getClassLoader();//app
//URL resource = classLoader.getResource("com/example/spring/demo/test/service");
URL resource = classLoader.getResource(path);
File file = new File(resource.getFile());
if (file.isDirectory()) {
File[] files = file.listFiles();
for (int i = 0; i < files.length; i++) {
// System.out.println("files[i] = " + files[i]);
// F:\ideaWorkV\springdemo\target\classes\com\example\spring\demo\test\service\UserService.class
// classLoader.loadClass("com.example.spring.demo.test.service.UserService");
String fileName = files[i].getAbsolutePath();
if (fileName.endsWith(".class")) {
String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
className = className.replace("\\", ".");
System.out.println("className = " + className);
Class clazz = classLoader.loadClass(className);
if (clazz.isAnnotationPresent(Component.class)) {
// 表示当前这个类是一个Bean
// Class--> bean? 解析类,判断当前bean是单例bean,还是prototype的bean
// BeanDefinitBean 解析类生成一个beanDefinitBean
Component componentAnnoation = (Component) clazz.getDeclaredAnnotation(Component.class);
String beanName = componentAnnoation.value();
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setClazz(clazz);
if (clazz.isAnnotationPresent(Scope.class)) {
Scope scopeAnnotaion = (Scope)clazz.getDeclaredAnnotation(Scope.class);
beanDefinition.setScope(scopeAnnotaion.value());
} else {
beanDefinition.setScope("singleton");
}
beanDefiniationMap.put(beanName, beanDefinition);//将bean的定义存储到map中
}
}
}
}
}
public Object getBean(String beanName) {
//根据类 判断是否是单例bean还是prototype的bean
if (beanDefiniationMap.containsKey(beanName)) {
BeanDefinition beanDefinition = (BeanDefinition) beanDefiniationMap.get(beanName);
if (beanDefinition.getScope().equals("singleton")) {
Object o = singletonObjects.get(beanName);
return o;
} else {
// 创建Bean对象
Object o = createBean(beanDefinition);
return o;
}
} else {
//不存在对应的bean
throw new NullPointerException();
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
//service 层 不写 spring解析类名
String value() default "";
}
/**
* 自定义扫描路径
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
//定义扫描路径 一般不用给默认值,使用该注解时候直接设置
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
String value();
}
- 创建userService,并指定bean的域为原型,(域分为单例和原型两种,单例地址不变化,原型bean地址不断变化)
@Component("userService")
@Scope("prototype")
public class UserService {
}
public class xxxUtil {
}
/**
*开启事务
*/
@ComponentScan("com.example.spring.demo.test.service")
public class AppConfig {
}
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
//传入参数为spring的配置文件参数
cjwApplicationContext context = new cjwApplicationContext(AppConfig.class);
Object userService = context.getBean("userService");//map<beanName,bean对象> 单例池
Object userService1 = context.getBean("userService");//map<beanName,bean对象> 单例池
Object userService2 = context.getBean("userService");//map<beanName,bean对象> 单例池
System.out.println("userService = " + userService);
System.out.println("userService1 = " + userService1);
System.out.println("userService2 = " + userService2);
}
}
二、相应的知识点
根据包名得到类 类加载器 以及对应的扫描路径位置
1、bootstrap --->jre/lib
2、ext --->jre/ext/lib
3、app --->classpath
@Retention
source:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;被编译器忽略
class:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期
runtime:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
这3个生命周期分别对应于:Java源文件(.java文件) ---> .class文件?--->?内存中的字节码。
@Target:
@Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、 类型成员(方法、构造方法、成员变量、枚举值)、 方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。
?
参考链接:深入理解Java类加载 - czwbig - 博客园
|