这篇文章主要带大家实现一个简单的Spring框架,包含单例、多例bean的获取,依赖注入、懒加载等功能。
一、创建Java项目
首先,需要创建一个Java工程,名字就叫spring。
创建完成后,如下图,再依次创建三级包
二、开始实现Spring
Spring中最重要也是最基础的类就是Spring容器,Spring容器用于创建管理对象,为了方便实现类型转换功能,给接口设置一个参数化类型(泛型)。
1、创建BeanFactory接口
BeanFactory是spring容器的顶级接口,在该接口中定义三个重载的获取bean的方法。
package com.example.spring;
/**
* @author heyunlin
* @version 1.0
*/
public interface BeanFactory<T> {
Object getBean(String beanName);
T getBean(Class<T> type);
T getBean(String beanName, Class<T> type);
}
2、创建ApplicationContext接口
ApplicationContext接口扩展自BeanFactory接口
package com.example.spring;
/**
* @author heyunlin
* @version 1.0
*/
public interface ApplicationContext<T> extends BeanFactory<T> {
}
3、创建ApplicationContext接口的实现类
创建一个ApplicationContext接口的实现类,实现接口中定义的所有抽象方法。
package com.example.spring;
/**
* @author heyunlin
* @version 1.0
*/
public class AnnotationConfigApplicationContext<T> implements ApplicationContext<T> {
@Override
public Object getBean(String beanName) {
return null;
}
@Override
public T getBean(Class<T> type) {
return null;
}
@Override
public T getBean(String beanName, Class<T> type) {
return null;
}
}
4、实现Spring IOC功能
首先,组件扫描需要一个扫描路径,可以通过配置类上的@ComponentScan注解指定,如果不指定,则默认为配置类所在的包。
创建配置类
在当前包下创建一个类,配置包扫描路径。
package com.example.spring;
/**
* @author heyunlin
* @version 1.0
*/
@ComponentScan("com.example.spring")
public class SpringConfig {
}
创建自定义注解
@Lazy
package com.example.spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author heyunlin
* @version 1.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Lazy {
boolean value() default false;
}
@Bean
package com.example.spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author heyunlin
* @version 1.0
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
String value();
}
@Scope
package com.example.spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author heyunlin
* @version 1.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Scope {
String value();
}
@Configuration
package com.example.spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author heyunlin
* @version 1.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface Configuration {
String value();
}
@Component
package com.example.spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author heyunlin
* @version 1.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
String value() default "";
}
@Repository
package com.example.spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author heyunlin
* @version 1.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface Repository {
String value();
}
@Service
package com.example.spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author heyunlin
* @version 1.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface Service {
String value();
}
@Controller
package com.example.spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author heyunlin
* @version 1.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface Controller {
String value();
}
@ComponentScan
package com.example.spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author heyunlin
* @version 1.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
String value();
}
创建bean的定义
package com.example.spring;
/**
* @author heyunlin
* @version 1.0
*/
public class BeanDefinition {
/**
* bean的类型
*/
private Class type;
/**
* bean的作用域
*/
private String scope;
/**
* 是否懒加载
*/
private boolean lazy;
public Class getType() {
return type;
}
public void setType(Class type) {
this.type = type;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public boolean isLazy() {
return lazy;
}
public void setLazy(boolean lazy) {
this.lazy = lazy;
}
}
修改AnnotationConfigApplicationContext
1、添加一个属性clazz,用于保存实例化时传递的配置类对象参数
2、Spring容器中创建用于保存bean的定义的map
3、创建单例对象池,也是一个map,保存单例bean
package com.example.spring;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author heyunlin
* @version 1.0
*/
public class AnnotationConfigApplicationContext<T> implements ApplicationContext<T> {
private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
/**
* 单例对象池
*/
private Map<String, Object> singletonObjects = new HashMap<>();
public final Class<T> clazz;
public AnnotationConfigApplicationContext(Class<T> clazz) throws ClassNotFoundException {
this.clazz = clazz;
// 扫描组件,保存到BeanDefinition中
scan(clazz);
// 把组件中非懒加载的单例bean保存到单例池
for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
String beanName = entry.getKey();
BeanDefinition beanDefinition = entry.getValue();
if(isSingleton(beanDefinition.getScope()) && !beanDefinition.isLazy()) {
Object bean = createBean(beanDefinition);
singletonObjects.put(beanName, bean);
}
}
}
/**
* 创建bean对象
* @param beanDefinition bean的定义
* @return Object 创建好的bean对象
*/
private Object createBean(BeanDefinition beanDefinition) {
Object bean = null;
Class beanType = beanDefinition.getType();
// 获取所有构造方法
Constructor[] constructors = beanType.getConstructors();
try {
/**
* 推断构造方法
* 1、没有提供构造方法:调用默认的无参构造
* 2、提供了构造方法:
* - 构造方法个数为1
* - 构造方法参数个数为0:无参构造
* - 构造方法参数个数不为0:传入多个为空的参数
* - 构造方法个数 > 1:推断失败,抛出异常
*/
// 无参构造方法
Constructor constructor = beanType.getConstructor();
bean = constructor.newInstance();
// if (isEmpty(constructors)) {
// // 无参构造方法
// Constructor constructor = beanType.getConstructor();
//
// bean = constructor.newInstance();
// } else if (constructors.length == 1) {
// Constructor constructor = constructors[0];
// // 得到构造方法参数个数
// int parameterCount = constructor.getParameterCount();
//
// if (parameterCount == 0) {
// // 无参构造方法
// bean = constructor.newInstance();
// } else {
// // 多个参数的构造方法
// Object[] array = new Object[parameterCount];
//
// bean = constructor.newInstance(array);
// }
// } else {
// throw new IllegalStateException();
// }
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
return bean;
}
private boolean isEmpty(Object[] array) {
return array.length == 0;
}
private boolean isSingleton(String scope) {
return "singleton".equals(scope);
}
private void scan(Class<T> clazz) throws ClassNotFoundException {
if (clazz.isAnnotationPresent(ComponentScan.class)) {
ComponentScan componentScan = clazz.getAnnotation(ComponentScan.class);
String value = componentScan.value();
if (!"".equals(value)) {
String path = value;
path = path.replace(".", "/");
URL resource = clazz.getClassLoader().getResource(path);
File file = new File(resource.getFile());
loopFor(file);
}
}
}
private void loopFor(File file) throws ClassNotFoundException {
if (file.isDirectory()) {
for (File listFile : file.listFiles()) {
if (listFile.isDirectory()) {
loopFor(listFile);
continue;
}
toBeanDefinitionMap(listFile);
}
} else if (file.isFile()) {
toBeanDefinitionMap(file);
}
}
private void toBeanDefinitionMap(File file) throws ClassNotFoundException {
String absolutePath = file.getAbsolutePath();
absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
absolutePath = absolutePath.replace("\\", ".");
Class<?> loadClass = clazz.getClassLoader().loadClass(absolutePath);
String beanName;
if (loadClass.isAnnotationPresent(Component.class)) {
Component component = loadClass.getAnnotation(Component.class);
beanName = component.value();
if ("".equals(beanName)) {
beanName = getBeanName(loadClass);
}
boolean lazy = false;
String scope = "singleton";
// 类上使用了@Scope注解
if (loadClass.isAnnotationPresent(Scope.class)) {
// 获取@Scope注解
Scope annotation = loadClass.getAnnotation(Scope.class);
// 单例
if (isSingleton(annotation.value())) {
if (loadClass.isAnnotationPresent(Lazy.class)) {
Lazy loadClassAnnotation = loadClass.getAnnotation(Lazy.class);
if (loadClassAnnotation.value()) {
lazy = true;
}
}
} else {
// 非单例
scope = annotation.value();
}
} else {
// 类上没有使用@Scope注解,默认是单例的
if (loadClass.isAnnotationPresent(Lazy.class)) {
Lazy annotation = loadClass.getAnnotation(Lazy.class);
if (annotation.value()) {
lazy = true;
}
}
}
// 保存bean的定义
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setType(loadClass);
beanDefinition.setLazy(lazy);
beanDefinition.setScope(scope);
beanDefinitionMap.put(beanName, beanDefinition);
}
}
/**
* 根据类对象获取beanName
* @param loadClass bean的Class对象
* @return String beanName
*/
private String getBeanName(Class<?> loadClass) {
String beanName = loadClass.getSimpleName();
// 判断是否以双大写字母开头
String className = beanName.replaceAll("([A-Z])([A-Z])", "$1_$2");
// 正常的大驼峰命名:bean名称为类名首字母大写
if (className.indexOf("_") != 1) {
beanName = beanName.substring(0, 1).toLowerCase().concat(beanName.substring(1));
}
// else { // 否则,bean名称为类名
// beanName = beanName;
// }
return beanName;
}
@Override
public Object getBean(String beanName) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition == null) {
throw new NullPointerException();
}
String scope = beanDefinition.getScope();
if (isSingleton(scope)) {
Object object = singletonObjects.get(beanName);
// 懒加载的单例bean
if (object == null) {
Object bean = createBean(beanDefinition);
singletonObjects.put(beanName, bean);
}
}
return singletonObjects.get(beanName);
}
@Override
public T getBean(Class<T> type) {
if (type == null) {
throw new IllegalStateException("bean类型不能为空!");
}
BeanDefinition beanDefinition = null;
// 保存指定类型的bean的个数
AtomicInteger count = new AtomicInteger();
for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
beanDefinition = entry.getValue();
Class beanType = beanDefinition.getType();
if (beanType.equals(type)) {
count.addAndGet(1);
}
}
if (count.get() == 0 || count.get() > 1) {
throw new IllegalStateException();
}
return (T) createBean(beanDefinition);
}
@Override
public T getBean(String beanName, Class<T> type) {
if (type == null) {
throw new IllegalStateException("bean类型不能为空!");
}
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (type.equals(beanDefinition.getType())) {
return (T) createBean(beanDefinition);
}
throw new IllegalStateException();
}
}
5、使用Spring获取bean对象
package com.example.spring;
/**
* @author heyunlin
* @version 1.0
*/
public class SpringExample {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
Object bean = applicationContext.getBean("beanName");
System.out.println(bean);
}
}