前面写过怎么通过Java的反射技术实现对象的创建和管理,达到IOC的效果。但是没有讲设计的思路,直接上代码,导致很多人没有思路,因此今天具体的讲IOC的编写思路理清。这里单纯的通过Java中的反射创建对象,至于扩展的部分会有提示思路
既然提到注解实现IOC,那么肯定要了解元注解的基本信息。
@Documented:被@Documented标注的类,在生成文档(doc)时,会显示@Documented注解信息。
@Inherited:可以被继承
@Target:可以声明的地方,通常为TYPE(类),FIELD(属性),METHOD(方法),
@Retention(RetentionPolicy.RUNTIME):参数有三个:CLASS,SOURCE,RUNTIME。
官方原文:注释保留策略。这种枚举类型的常量描述了保留注释的各种策略。它们与Retention元注释类型
结合使用,以指定注释要保留多长时间
1.RetentionPolicy.SOURCE —— 注释将被编译器丢弃(信息仅保留在源代码中,编译时将其忽略)。
2.RetentionPolicy.CLASS —— 注释将由编译器记录在类文件中,但不需要在运行时由 JVM 保留。这是默认行为
(编译时保留,将信息保留在CLASS文件中)。
3.RetentionPolicy.RUNTIME —— 注释将由编译器记录在类文件中,并在运行时由 JVM 保留,因此可以反射性地
读取它们(使用反射,其实就是在运行时通过JVM读取信息,类似于js脚本动态操作,这也是我们使用反射的用途)
上面简单的了解了一下元注解信息,创建注解类:@Annotation
这里即下面的例子,会参考SpringBoot的启动方式进行编写,演示一下IOC的原理,至于扩展的部分留给各位去发挥。
创建注解类:
Value普通属性值注入
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
String value() default "";
}
Component组件(对象)创建
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Component {
String value() default "";//这不是数组,也不是方法,这是注解的属性声明,可以声明默认资,
//也可不声明,String[] value()声明其为数组的形式
}
Autowared自动注入(赋值)
@Inherited
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowared {
String value() default "";
}
AnnotationBootStrap启动类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationBootStrap {
boolean value() default true;
}
ComponentScanPackage类,自定义扫描包
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScanPackage {
String value();
}
到此,基本信息创建成功。(思路:获得包路径 ---->扫描项目文件夹---->> 提取class文件 ---->>提取class全限定类名 —>> 通过Class.from创建类对象---->>获得无参构造---->>加入缓存---->遍历无参构造属性上注解信息进行赋值---->处理基本类型----->通过遍历缓存进行自动注入(注意:这里我设计的不够好,可能会产生null值,但不存在循环依赖问题)---->创建成功 )通过启动类,需要获取注解信息,因此需要获得类路径:
创建ApplicationContextAnnotationBeanFactory类(通过无参构造器创建实例,否则报错【这里可以发挥自己的想法,方法不止一个】(可以参考一下Spring解决循环依赖的缓存策略,设计三级缓存思路))
public class ApplicationContextAnnotationBeanFactory implements ApplicationContextBeanFactory {
private Map<String, Object> objectMap;
private List<Class> classList;
//初始化构造器,先判断是否具备启动条件
public ApplicationContextAnnotationBeanFactory(Class cls) throws Exception {
if (!cls.isAnnotationPresent(AnnotationBootStrap.class)) {
throw new RuntimeException(cls+"不是一个启动类,没有AnnotationBootStrap注解");
} else {
AnnotationBootStrap bootStrap = (AnnotationBootStrap) cls.getAnnotation(AnnotationBootStrap.class);
if (bootStrap.value()) {
//获得项目中的带有注解的Class
this.classList = getClassList(cls);
//获得Component标注的类对象实例
objectMap = createObject();
} else {
throw new RuntimeException("AnnotationBootStrap启动类没有开启:false");
}
}
}
@Override
public Object getBean(String name) throws ClassNotFoundException {
return objectMap.get(name);
}
@Override
public <T> T getBean(String name, Class cls) throws ClassNotFoundException {
return (T) objectMap.get(name);
}
@Override
public Integer getBeanSize() {
return objectMap.size();
}
@Override
public List<Object> getBeanList() {
List<Object> list = new ArrayList<>();
for (String beanName : objectMap.keySet()) {
list.add(objectMap.get(beanName));
}
return list;
}
@Override
public List<Class> getClassList(Class cls) throws ClassNotFoundException, FileNotFoundException {
return new ScanPackagePath().scanPackagerPath(cls);
}
@Override
public Map<String, Object> createObject() throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
CreateFactoryBean createFactoryBean = new CreateFactoryBean();
objectMap = createFactoryBean.getNoConstructor(classList);
return objectMap;
}
}
CreateFactoryBean类,创建Component标注的class
public class CreateFactoryBean {
public Map<String, Object> getNoConstructor(List<Class> classList) throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
Map<String, Object> objectMap = new HashMap<>();
getNoConstructorObject(classList, objectMap);
return objectMap;
}
/**
* 创建注解无参构造的对象,将其加入容器
*/
private void getNoConstructorObject(List<Class> classList, Map<String, Object> objectMap) throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
for (Class aClass : classList) {
if (aClass.isAnnotationPresent(Component.class)) {
Component component = (Component) aClass.getAnnotation(Component.class);
String beanName = null;
if (component.value().equals("")) {
beanName = aClass.getName();//如果没有设置自定义名字,则将全路径名作为名字
} else {
beanName = component.value();//得到自定义名称
}
Constructor constructor = aClass.getConstructor();//获得无参构造
Object o = constructor.newInstance();//创建对象
setParameter(o);//初始化参数
objectMap.put(beanName, o);
}
}
setObjectParameter(objectMap);
}
/**
* 对引用的对象类型进行赋值
*/
private void setObjectParameter(Map<String, Object> objectMap) throws IllegalAccessException {
for (String s : objectMap.keySet()) {
Class aClass = objectMap.get(s).getClass();
Field[] fields = aClass.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowared.class)) {
Autowared autowared = field.getAnnotation(Autowared.class);
String value = autowared.value();
field.setAccessible(true);
if (value.equals("")){
for (String bean : objectMap.keySet()) {
if (field.getType().isAssignableFrom(objectMap.get(bean).getClass())
||objectMap.get(bean).getClass().isAssignableFrom(field.getType())){
field.set(objectMap.get(s),objectMap.get(bean));
break;
}
}
}else{
field.set(objectMap.get(s),objectMap.get(value));
}
}
}
}
}
/**
* 注入注解的值
*/
public void setParameter(Object o) throws IllegalAccessException {
for (Field field : o.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(Value.class)) {
Value value = field.getAnnotation(Value.class);
String value1 = value.value();
field.setAccessible(true);
if (isPrimitive(field)) {
setPrimitive(o, value1, field);
} else {
field.set(o, value1);
}
}
}
}
/**
* 配置基本数据类型
*/
private void setPrimitive(Object o, String value1, Field field) throws IllegalAccessException {
if (field.getType().isAssignableFrom(int.class) || field.getType().isAssignableFrom(Integer.class)) {
field.set(o, Integer.parseInt(value1));
}else if (field.getType().isAssignableFrom(short.class) || field.getType().isAssignableFrom(Short.class)){
field.set(o, Short.parseShort(value1));
}else if (field.getType().isAssignableFrom(long.class) || field.getType().isAssignableFrom(Long.class)){
field.set(o,Long.parseLong(value1));
}else if (field.getType().isAssignableFrom(char.class)) {
field.set(o, value1.charAt(0));
}else if (field.getType().isAssignableFrom(byte.class) || field.getType().isAssignableFrom(Byte.class)){
field.set(o,Byte.parseByte(value1));
}else if (field.getType().isAssignableFrom(Boolean.class) || field.getType().isAssignableFrom(boolean.class)) {
field.set(o, Boolean.parseBoolean(value1));
} else if (field.getType().isAssignableFrom(float.class) || field.getType().isAssignableFrom(Float.class)) {
field.set(o,Float.parseFloat(value1));
} else if (field.getType().isAssignableFrom(double.class) || field.getType().isAssignableFrom(Double.class)) {
field.set(o,Long.parseLong(value1));
}
}
/**
* 判断属性的类型是否为基本类型
*/
private boolean isPrimitive(Field value) {
if (value.getType().isPrimitive()) {
return true;
}
return false;
}
}
ScanPackagePath类,扫描包路径
public class ScanPackagePath {
/**
*扫描启动类的包路径
*/
public List<Class> scanPackagerPath(Class cls) throws ClassNotFoundException, FileNotFoundException {
String path = cls.getClassLoader().getResource("").getPath();
String path1 = cls.getPackageName();
if (isOnePath(cls)) {//判断是否为同一个路径
return getClassList(path, path1);
} else {
List<Class> list = null;
if (cls.isAnnotationPresent(ComponentScanPackage.class)) {
ComponentScanPackage clsAnnotation = (ComponentScanPackage) cls.getAnnotation(ComponentScanPackage.class);
String value = clsAnnotation.value();
list = getClassList(path, value);
}
List<Class> list1 = getClassList(path, path1);
for (Class aClass : list1) {
list.add(aClass);
}
return list;
}
}
/**
* 判断是否是同一路径
*/
private boolean isOnePath(Class cls) {
if (cls.isAnnotationPresent(ComponentScanPackage.class)) {
ComponentScanPackage clsAnnotation = (ComponentScanPackage) cls.getAnnotation(ComponentScanPackage.class);
String path1 = clsAnnotation.value();
String path2 = cls.getPackageName();
if (path1.equals(path2) || path2.equals("") || path1.contains(path2) || path2.contains(path1)) {
return true;
} else {
return false;
}
}
return true;
}
/**
*获得Class集合
*/
private List<Class> getClassList(String classPath, String packageName) throws ClassNotFoundException, FileNotFoundException {
List<Class> list = new ArrayList<>();
String replace = packageName.replace(".", File.separator);
File file = new File(classPath, replace);
File file1 = new File(classPath);
if (!file.exists()) {
throw new FileNotFoundException(packageName + "不存在");
}
getClassObject(file,file1.getPath(), list);
return list;
}
/**
*获得Class类对象
*/
private void getClassObject(File file,String classPath, List<Class> list) throws ClassNotFoundException {
File[] files = file.listFiles();
for (File cls : files) {
if (cls.isDirectory()) {
getClassObject(cls,classPath, list);
} else {
if (cls.isFile()) {
if (cls.getName().endsWith(".class")) {
String clsPath = cls.getPath();
Class aClass = createClass(clsPath,classPath);
if (aClass != null) {
list.add(aClass);
}
}
}
}
}
}
/**
* 创建对象
*/
private Class createClass(String classPath, String path) throws ClassNotFoundException {
//获得类的全限定类名
String cls = classPath.substring(path.length()+1,classPath.length()-6).replace(File.separator,".");
Class aClass = Class.forName(cls);
return (aClass.isInterface()||aClass.isAnnotation())?null:aClass;
}
}
容器ApplicationContext父接口
public interface ApplicationContext {
Object getBean(String name) throws ClassNotFoundException;
<T> T getBean(String name,Class cls)throws ClassNotFoundException;
Integer getBeanSize();
List<Object> getBeanList();
}
ApplicationContextBeanFactory二级接口(这里设计的不好,可以合并到ApplicationContext)
public interface ApplicationContextBeanFactory extends ApplicationContext {
List<Class> getClassList(Class cls) throws ClassNotFoundException, FileNotFoundException;
Map<String,Object> createObject() throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException;
}
ApplicationContextBeanFactory的实现类ApplicationContextAnnotationBeanFactory
public class ApplicationContextAnnotationBeanFactory implements ApplicationContextBeanFactory {
private Map<String, Object> objectMap;
private List<Class> classList;
public ApplicationContextAnnotationBeanFactory(Class cls) throws Exception {
if (!cls.isAnnotationPresent(AnnotationBootStrap.class)) {
throw new RuntimeException(cls+"不是一个启动类,没有AnnotationBootStrap注解");
} else {
AnnotationBootStrap bootStrap = (AnnotationBootStrap) cls.getAnnotation(AnnotationBootStrap.class);
if (bootStrap.value()) {
this.classList = getClassList(cls);
objectMap = createObject();
} else {
throw new RuntimeException("AnnotationBootStrap启动类没有开启:false");
}
}
}
@Override
public Object getBean(String name) throws ClassNotFoundException {
return objectMap.get(name);
}
@Override
public <T> T getBean(String name, Class cls) throws ClassNotFoundException {
return (T) objectMap.get(name);
}
@Override
public Integer getBeanSize() {
return objectMap.size();
}
@Override
public List<Object> getBeanList() {
List<Object> list = new ArrayList<>();
for (String beanName : objectMap.keySet()) {
list.add(objectMap.get(beanName));
}
return list;
}
@Override
public List<Class> getClassList(Class cls) throws ClassNotFoundException, FileNotFoundException {
return new ScanPackagePath().scanPackagerPath(cls);
}
@Override
public Map<String, Object> createObject() throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
CreateFactoryBean createFactoryBean = new CreateFactoryBean();
objectMap = createFactoryBean.getNoConstructor(classList);
return objectMap;
}
}
启动类
@AnnotationBootStrap//声明该类为启动类(默认为true,false表示不启动该功能)
@ComponentScanPackage("cn.edu.mapper")//扫描包(可以不声明,默认使用该类的包路径)
public class MyTestAnnotation {
public static void main(String[] args) throws Exception {
ApplicationContext app = new ApplicationContextAnnotationBeanFactory(MyTestAnnotation.class);
User user = (User) app.getBean("user");
System.out.println(user);
}
}
实体类
@Component("test")
public class Test {
@Value("杨万里")
private String name;
public void print(){
System.out.println("Hello,I am advance notice");
}
@Override
public String toString() {
return "Test{" +
"name='" + name + '\'' +
'}';
}
}
@Component("user")
public class User {
@Value("貂蝉")
private String name;
@Value("女")
private String sex;
@Value("3")
private int age;
@Autowared
private Test test;
public User() {
}
public User(String name, String sex, int age, Test test) {
this.name = name;
this.sex = sex;
this.age = age;
this.test = test;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
", test=" + test +
'}';
}
}
运行结果
在写这个IOC的时候,边写边想,所有在设计上思路并没有太清晰,整体上存在一些缺陷,请见谅。各位在参考这篇文章的时候,可以结合JDK动态代理和Cglib,参考Spring的基本原理可以达到更好的效果(此处没有对接口进行管理)。注意哦:private修饰的属性和方法注解类不能被继承,Spring中条件注解Condidtion条件注解是一个很好的参考源码地址,Gitee