BeanFactory
IOC
ioc是指(Inversion of Control)也就是控制反转。
在设计模式中有一种模式叫做单例模式,如果对于一个类只作于方法调用而不保存任何状态的,我们就一般只创建一个对象用过来使用,这种模式就叫单例模式。
例如
1.有状态的
@Data
public class User{
private String name;
private Interage age;
}
这种user类创建出来的对象就是有状态的。
2.无状态的
public class UserService{
public Reuslt login(...){
....
}
}
这样的类创建出来的对象只用于做方法调用的就是无状态的。
Bean
Bean就是描述Java的软件组件模型,一般是代表那种无状态的类的对象,在项目启动前就new了Bean对象并且放到了容器里面,需要用的时候就从容器里取
Bean容器
一般是存放Bean的一个Map集合,可以在项目启动前调用一个init()方法如下面代码
public class BeanFactory {
private Map<Class<?>,Object> beanContext;
public Map<Class<?>, Object> getBeanContext() {
if(beanContext==null)beanContext=new HashMap<>();
return beanContext;
}
public void putBean(Class<?> clazz,Object o){
if(beanContext==null)beanContext=new HashMap<>();
beanContext.put(clazz,o);
}
public void setBeanContext(Map<Class<?>, Object> context) {
beanContext= context;
}
public <T> T getBean(Class<T> clazz) {
if(beanContext==null||(!beanContext.containsKey(clazz)))return null;
return (T)beanContext.get(clazz);
}
}
将Bean的对象存放在BeanContext里面,如果需要用的时候就调用getBean方法就能获取到Bean对象了。
例子:
比如我们现在有个Bean类叫UserService
public class UserService{
.....
}
那么我们的init方法可以这样写
public class PojectInit{
public BeanFactory init(){
BeanFactory beanFactory = new BeanFactory();
beanFactory.put(UserService.class,new UserService());
return beanFactory;
}
}
这样就能将东西全部放进去了
反射
虽然BeanFactory很好,但是如果我的Bean多了怎么办,那么我岂不是要写很多的beanFactory.put();
为了解决这个问题,我们可以采用一下java的反射机制,配合注解去使用
我们可以定义一个Bean注解
@Target({ElementType.TYPE,ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Bean {
}
当我们想设置一个类为Bean类的话我们可以这样写
@Bean
public class UserService{
.....
}
接下来就是下一个问题,我们如何将带有@Bean的类实例化放入BeanContext呢,当然是全局扫描
public class PojectInit{
public BeanFactory init(Class<?> clazz){
BeanFactory beanFactory=new BeanFactory();
String[] split = clazz.getName().split("\\.");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < split.length-1; i++) {
sb.append(split[i]).append(".");
}
if(sb.charAt(sb.length()-1)=='.')sb.deleteCharAt(sb.length()-1);
classpath=sb.toString();
String path = Objects.requireNonNull(clazz.getResource("")).getPath();
initBean(new File(path));
return beanFactory;
}
private void initBean(File file){
if(file.isDirectory()){
File[] files = file.listFiles();
assert files != null;
for (File pathFile : files) {
if (pathFile.isDirectory()) {
initBean(pathFile);
continue;
}
if (pathFile.getName().contains(".class")) {
String className = pathFile.getPath().substring(pathFile.getPath().indexOf(classpath)).replace(".class", "").replace("\\", ".");
try {
Class<?> obj = Class.forName(className);
if (!isBean(obj)) {
continue;
}
if(obj.isAnnotation()){
continue;
}
if(obj.isInterface()){
beanFactory.putBean(obj,null);
//执行接口方法
continue;
}
if(!obj.isPrimitive()){
Class<?>[] interfaces = obj.getInterfaces();
if(interfaces.length>0){
beanFactory.putBean(interfaces[0],obj.newInstance());
}else {
beanFactory.putBean(obj,obj.newInstance());
}
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
private boolean isBean(Class<?> clazz){
return isAnnotation(clazz, Bean.class);
}
private boolean isAnnotation(Annotation annotation, List<Class<?>> list, Class<? extends Annotation> annotationClazz){
if (annotation.annotationType().getAnnotation(annotationClazz)!=null)return true;
if(list.contains(annotation.annotationType()))return false;
list.add(annotation.annotationType());
Class<?> annotationType = annotation.annotationType();
Annotation[] annotations = annotationType.getDeclaredAnnotations();
boolean flag=false;
for (Annotation an : annotations) {
flag=flag||isAnnotation(an,list,annotationClazz);
}
return flag;
}
private boolean isAnnotation(Class<?> clazz,Class<? extends Annotation> annotationClazz){
if (clazz.getAnnotation(annotationClazz)!=null)return true;
boolean flag= false;
for (Annotation annotation : clazz.getDeclaredAnnotations()) {
flag=flag|| AnnotationUtils.isAnnotation(annotation, new ArrayList<>(), annotationClazz);
}
return flag;
}
}
main方法我们可以这样写
public class Main{
public static void main(){
BeanFactory beanFactory = new PojectInit().init(Main.class);
}
}
这样就能得到一个BeanFactory的对象,里面就会自动去扫描@Bean的类。
代码可能有考虑不周到,现在目前在自己学习写Spring的东西,写的不是很好,欢迎各位评论和指点一下。
这个是我目前在学习Spring底层的时候自己的理解实现的代码,开源地址
https://github.com/WhiteEnzuo/StudySpring
我会不断的去更新内容和我的代码。