项目的初始化结构如上图,模拟spring中的注解和加载方式,首先是ComponentScan ,Component,
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {
String value() default "";
}
@ComponentScan("com.guojia.service")
public class AppConfig {
}
@Component
public class OrderService {
}
@Component("userService")
public class UserService {
@Autowired
private OrderService orderService;
public void test(){
System.out.println("userServiceTest");
}
}
public class Test {
public static void main(String[] args) {
GuojiaApplicationContext applicationContext = new GuojiaApplicationContext(AppConfig.class);
UserService userService = (UserService) applicationContext.getBean("userService");
userService.test();
}
}
// 由于Test类的main方法中类需要加载参数
public class GuojiaApplicationContext {
private Class configClass;
private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
private Map<String,Object> singletonObjects = new HashMap<>();
public GuojiaApplicationContext(Class<?> configClass) {
this.configClass = configClass;
scan(configClass);
}
private void scan(Class<?> configClass) {
// 如果存在这个注解
if (configClass.isAnnotationPresent(ComponentScan.class)) {
ComponentScan componentScan = configClass.getAnnotation(ComponentScan.class);
// 注解所在的target文件夹的位置
String path = componentScan.value();
path = path.replace(".", "/");
System.out.println("ComponentScan路径:" + path);
ClassLoader classLoader = this.getClass().getClassLoader();
URL resource = classLoader.getResource(path);
File file = new File(resource.getFile());
if (file.isDirectory()) {
for (File f : Objects.requireNonNull(file.listFiles())) {
String absolutePath = f.getAbsolutePath();
absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
absolutePath = absolutePath.replace("\\", ".");
try {
Class<?> clazz = classLoader.loadClass(absolutePath);
if(clazz.isAnnotationPresent(Component.class)){
Component component = clazz.getAnnotation(Component.class);
String beanName = component.value();
// 默认类名小写开头
if("".equals(beanName)){
beanName = Introspector.decapitalize(clazz.getSimpleName());
System.out.println(beanName);
}
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setType(clazz);
beanDefinitionMap.put(beanName,beanDefinition);
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
}
}
//模拟getBean方法
public Object getBean(String beanName) {
if(!beanDefinitionMap.containsKey(beanName)){
throw new NullPointerException(beanName+"未加载");
}
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if("singleton".equals(beanDefinition.getScope())){
Object singleton = singletonObjects.get(beanName);
if(singleton==null){
singletonObjects.put(beanName,createBean(beanName,beanDefinition));
}
return singleton;
}else {
Object bean = createBean(beanName,beanDefinition);
return bean;
}
}
private Object createBean(String beanName, BeanDefinition beanDefinition) {
Class clazz = beanDefinition.getType();
try {
Object instance = clazz.getConstructor().newInstance();
for(Field field : clazz.getDeclaredFields()){
if(field.isAnnotationPresent(Autowired.class)){
field.setAccessible(true);
field.set(instance,getBean(field.getName()));
}
}
return instance;
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
执行main方法后
另外,我们也可以在UserService上加@Scope注解,来实现单例或者其他类型
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Scope {
String value() default "";
}
@Component("userService")
@Scope("singleton")
public class UserService {
public void test(){
System.out.println("userServiceTest");
}
}
在GuojiaApplicationContext的scan方法中添加
if (clazz.isAnnotationPresent(Component.class)) {
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setType(clazz);
beanDefinition.setLazy(clazz.isAnnotationPresent(Lazy.class));
if (clazz.isAnnotationPresent(Scope.class)) {
beanDefinition.setScope(clazz.getAnnotation(Scope.class).value());
} else {
beanDefinition.setScope("singleton");
}
String beanName = clazz.getAnnotation(Component.class).value();
if (beanName.isEmpty()) {
beanName = Introspector.decapitalize(clazz.getSimpleName());
}
beanDefinitionMap.put(beanName, beanDefinition);
}
同理,如果在Userservice上添加@Lazy注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Lazy {
boolean value() default true;
}
@Component("userService")
@Scope("singleton")
@Lazy
public class UserService {
public void test(){
System.out.println("userServiceTest");
}
}
需要在GuojiaApplicationContext的scan方法中添加
if(clazz.isAnnotationPresent(Lazy.class)){
beanDefinition.setLazy(clazz.getAnnotation(Lazy.class).value());
}
我们的注解类型添加到beanMap里面后,需要创建bean,如果使用bean,直接根据beanName获取到对应的对象
所以我们需要遍历beanDefinitonMap,如果是单例的存储到singletonObjects 的map里面,getBean使用的时候直接去singletonObjects里面取
public GuojiaApplicationContext(Class<?> configClass) {
this.configClass = configClass;
scan(configClass);
for (String beanName : beanDefinitionMap.keySet()) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition.getScope().equals("singleton") && !beanDefinition.isLazy()) {
Object bean = createBean(beanName, beanDefinition);
singletonObjects.put(beanName, bean);
}
}
}
public Object getBean(String beanName) {
if(!beanDefinitionMap.containsKey(beanName)){
throw new NullPointerException(beanName+"未加载");
}
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if("singleton".equals(beanDefinition.getScope())){
Object singleton = singletonObjects.get(beanName);
if(singleton==null){
singletonObjects.put(beanName,createBean(beanName,beanDefinition));
}
return singleton;
}else {
Object bean = createBean(beanName,beanDefinition);
return bean;
}
}
spring的bean生命周期有BeanNameAware ,如果我们的OrderService实现了BeanNameAware接口
public interface BeanNameAware {
void setBeanName(String name);
}
@Component
public class OrderService implements BeanNameAware {
@Override
public void setBeanName(String name) {
}
}
我们需要在GuojiaApplicationContext的createBean方法里面添加对应的处理
Class clazz = beanDefinition.getType();
try {
Object instance = clazz.getConstructor().newInstance();
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
field.setAccessible(true);
field.set(instance, getBean(field.getName()));
}
}
if(instance instanceof BeanNameAware){
((BeanNameAware) instance).setBeanName(beanName);
}
如果orderService还实现了ApplicationContextAware接口,则
public interface ApplicationContextAware {
void setApplicationContext(ZhouyuApplicationContext applicationContext);
}
@Component
public class OrderService implements BeanNameAware, ApplicationContextAware {
private GuojiaApplicationContext applicationContext;
private String beanName;
@Override
public void setBeanName(String name) {
this.beanName = name;
}
@Override
public void setApplicationContext(GuojiaApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
在BeanNameAware下面接着写对应的代码
if (instance instanceof ApplicationContextAware) {
((ApplicationContextAware) instance).setApplicationContext(this);
}
如果我们OrderService上添加了@Transactional 注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Transactional {
}
需要在上方的if方法下接着写
if (clazz.isAnnotationPresent(Transactional.class)) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
Object target = o;
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("开启事务");
Object result = method.invoke(target, objects);
System.out.println("提交事务");
return result;
}
});
o = enhancer.create();
}
以上是一些spring的注解模拟,下一篇文章是实际的spring中对应的类和方法讲解