阶段1:
编写自己的Spring容器,实现扫描包,得到bean的class对象.
思路:
使用 ElfSpringConfig.java 替代beans.xml文件作为配置文件,从中获取到:
1.扫描包,得到bean的class对象.
2.排除包下不是bean的
1.容器文件 ElfSpringApplicationContext.java 核心!!!
java
package com.elf.spring.ioc;
import com.elf.spring.annotation.*;
import java.io.File;
import java.net.URL;
/**
* @author 45~
* @version 1.0
*/
public class ElfSpringApplicationContext {
//第一步,扫描包,得到bean的class对象,排除包下不是bean的,因此还没有放到容器中
//因为现在写的spring容器比原先的基于注解的,要更加完善,所以不会直接把它放在ConcurrentHashMap
private Class configClass;
//构造器
public ElfSpringApplicationContext(Class configClass) {
this.configClass = configClass;
/**获取要扫描的包:
1.先得到ElfSpringConfig配置的 @ComponentScan(value= "com.elf.spring.component")
2.通过 @ComponentScan的value => 即要扫描的包 **/
ComponentScan componentScan =
(ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
String path = componentScan.value();
System.out.println("要扫描的包path=" + path);
/**
* 得到要扫描包下的所有资源(类.class)
* 1.得到类的加载器 -> APP类加载器是可以拿到 target目录下的classes所有文件的
* 2.通过类的加载器获取到要扫描的包的资源url => 类似一个路径
* 3.将要加载的资源(.class)路径下的文件进行遍历 => io
*/
ClassLoader classLoader = ElfSpringApplicationContext.class.getClassLoader();
path = path.replace(".", "/"); // 把.替换成 /
URL resource = classLoader.getResource(path);
System.out.println("resource=" + resource);
File file = new File(resource.getFile());
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) { //把所有的文件都取出来
System.out.println("============================");
System.out.println("f.getAbsolutePath()=" + f.getAbsolutePath());
String fileAbsolutePath = f.getAbsolutePath();//到target的classes目录下了
//这里只处理.class文件
if (fileAbsolutePath.endsWith(".class")) {
//1.获取类名
String className = fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1,
fileAbsolutePath.indexOf(".class"));
//2.获取类的完整路径(全类名)
String classFullName = path.replace("/", ".") + "." + className;
System.out.println("classFullName=" + classFullName);
//3.判断该类是否需要注入,就看是不是有注解@Component @Service @Contoller @Re....
try {
Class<?> clazz = classLoader.loadClass(classFullName);
if (clazz.isAnnotationPresent(Component.class) ||
clazz.isAnnotationPresent(Controller.class) ||
clazz.isAnnotationPresent(Service.class) ||
clazz.isAnnotationPresent(Repository.class)) {
//演示机制
//如果该类使用了@Component注解,说明是一个Spring bean
System.out.println("这是一个Spring bean=" + clazz + " 类名=" + className);
}
// Component component = clazz.getDeclaredAnnotation(Component.class);
// String id = component.value();
// if (!"".endsWith(id)) {
// className = id;//替换
// }
else {
//如果该类没有使用了@Component注解,说明是一个Spring bean
System.out.println("这不是一个Spring bean" + clazz + " 类名=" + className);
}
// Class<?> Class = Class.forName(classFullName);
// Object instance = Class.newInstance();
// ioc.put(StringUtils.uncapitalize(className), instance);
} catch (Exception e) {
e.printStackTrace();
}
}
}//遍历文件for循环结束
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
}//构造器结束
//编写放法返回容器中的对象
public Object getBean(String name) {
return null;
}
}
2.AppMain.java
java
package com.elf.spring;
import com.elf.spring.ioc.ElfSpringApplicationContext;
import com.elf.spring.ioc.ElfSpringConfig;
/**
* @author 45~
* @version 1.0
*/
public class AppMain {
public static void main(String[] args) {
//把容器创建起来,在创建的时候传入了配置类的class类型/class对象
//传进去后会根据自己写的容器机制 进行解析
ElfSpringApplicationContext elfSpringApplicationContext =
new ElfSpringApplicationContext(ElfSpringConfig.class);
}
}
3.配置文件 ElfSpringConfig.java
java
package com.elf.spring.ioc;
import com.elf.spring.annotation.ComponentScan;
/**
* @author 45~
* @version 1.0
* 这是一个配置类,作用类似于原生spring的beans.xml容器配置文件
*/
@ComponentScan(value= "com.elf.spring.component")
public class ElfSpringConfig {
}
4.component包下的类car / monsterDao / monsterService
java
package com.elf.spring.component;
/**
* @author 45~
* @version 1.0
*/
public class car {
}
java
package com.elf.spring.component;
import com.elf.spring.annotation.Component;
/**
* @author 45~
* @version 1.0
* 写第二个类是因为要有两个类才能做依赖注入
*/
@Component(value = "monsterDao")
public class MonsterDao {
}
java
package com.elf.spring.component;
import com.elf.spring.annotation.Component;
/**
* @author 45~
* @version 1.0
* 说明 MonsterService 是一个Servic
*/
@Component //把MonsterService注入到我们自己的spring容器中
public class MonsterService {
}
5.annotation包下的一堆自定义注解 ComponentScan + 经典4
java
package com.elf.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author 45~
* @version 1.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
String value() default "";
}
java
package com.elf.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author 45~
* @version 1.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
//通过value可以给注入的bean/对象指定名字
String value() default "";
}
java
package com.elf.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author 45~
* @version 1.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
//通过value可以给注入的bean/对象指定名字
String value() default "";
}
java
package com.elf.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author 45~
* @version 1.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Repository {
//通过value可以给注入的bean/对象指定名字
String value() default "";
}
java
package com.elf.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author 45~
* @version 1.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {
//通过value可以给注入的bean/对象指定名字
String value() default "";
}