视频教程连接
点击进入
本文实现的注解有
- @Component
- @Value
- @Autowired
- @Qualifier
实现的效果
实现这些IOC的思路
1. 获取到我们要管理的Class对象
我们首先要扫描我们要用的包 然后获取到所有有我们定义的@myComponent注解的Class对象 然后把这些Class和他们的名字给封装到一个对象里面
然后我们把获取到的所有对象给放到一个Set集合里面提供给下面步骤的使用
2.实例化要管理的对象 把初始化之后的对象给放到Map容器里面
- 在第一步的时候我们获取到了所有要管理的MyBeanDefinition
因为这个对象里面有Class 我们可以直接用反射去用
clazz.newInstance();调用无参构造方法实例化 - 然后我们通过反射获取@myValue注解里面的值 然后用反射调用set方法把值给赋进去
这样我们的对象就能初始化了 - 我们还需要把这个初始化之后的对象给设置一个名字 根据spring的习惯来说 默认命名都是类 的首字母小写 这一步我们直接把第一步获取到的BeanName处理一下就行了
- 最后我们把初始化好的 还有他的名字给放到一个Map集合里面 这样一个容器就差不多快做成了
3.依赖注入的实现
- 去遍历我们在第一步做好的那个Set 然后找到有@myAutowired这个注解标记的变量
@myAutowired是根据类型自动注入 或者说就是根据类型的名字去第二部的那个Map容器里面去找名字(key)一样的对象然后赋值 @myQualifier是根据注解里面的value去Map容器里面找对象 - 我们获取到有@myAutowired注解的变量的时候还要检查他有没有被 @myQualifier标记
如果有就根据value找第二步初始化之后的对象 没的话就自动注入就行了
具体实现步骤
注解
这四个注解的使用位置不同 但是我让他们都保存到运行时了
@myAutowired是自动根据类型名注入
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface myAutowired {
}
@myComponent标记该类让他被我写的ioc管理
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface myComponent {
String value() default "";
}
@myQualifier是根据value去注入
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface myQualifier {
String value();
}
@myValue是根据value的值给实例化对象赋值
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface myValue {
String value();
}
MyBeanDefinition 存放Class和ClassName
public class MyBeanDefinition {
private String BeanName;
private Class beanClass;
@Override
public String toString() {
return "MyBeanDefinition{" +
"BeanName='" + BeanName + '\'' +
", beanClass=" + beanClass +
'}';
}
public String getBeanName() {
return BeanName;
}
public void setBeanName(String beanName) {
BeanName = beanName;
}
public Class getBeanClass() {
return beanClass;
}
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}
public MyBeanDefinition(String beanName, Class beanClass) {
BeanName = beanName;
this.beanClass = beanClass;
}
}
MyAnnotationConfigApplicationContext(重点 IOC的核心)
就和上面思路里面说的一样 分三步走就好了
第一步的实现 获取到我们要管理的Class对象的
我们直接用工具就好了 获取到存放所有class的Set集合 然后通过迭代器遍历
不处理的话名字是这样的 如果把这个当成Bean的名字太长了 就截取最后的类名就行
思路第二步的实现 实例化并且初始化把对象给放到Map容器里面
第三步 把我们的存入map的bean给赋值到需要的地方
手动指定bean
自动注入
全部代码如下
public class MyAnnotationConfigApplicationContext{
private Map<String, Object> map = new HashMap();
public MyAnnotationConfigApplicationContext(String pack) {
//扫描包下所有的class 吧有mybean注解的都放到set里面
Set<MyBeanDefinition> beanDefinitions = findBeanDefinitions(pack);
//根据set里面的beanDefinitions来 创建对象放到map里面
createObject(beanDefinitions);
//把map里面的对像给自动装配
autowireObject(beanDefinitions);
}
public Object getBean(String name){
return map.get(name);
}
public void autowireObject(Set<MyBeanDefinition> beanDefinitions) {
Iterator<MyBeanDefinition> iterator = beanDefinitions.iterator();
while(iterator.hasNext()){
MyBeanDefinition next = iterator.next();
Class beanClass = next.getBeanClass();
for (Field declaredField : beanClass.getDeclaredFields()) {
myAutowired annotation = declaredField.getAnnotation(myAutowired.class);
if (annotation!=null){
//根据bean的name获取bean
myQualifier declaredannotation = declaredField.getAnnotation(myQualifier.class);
if (declaredannotation!=null){
try {
String beanName = declaredannotation.value();
Object bean = getBean(beanName);
String fieldName = declaredField.getName();
String methodName = "set"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1);
Method method = null;
method = beanClass.getMethod(methodName, declaredField.getType());
Object object = getBean(next.getBeanName());
method.invoke(object, bean);
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}else{
//自动装配 获取到
try {
String name = declaredField.getType().getName();
String className = name.replaceAll( beanClass.getPackage().getName() + ".", "");
String beanName = className.substring(0, 1).toLowerCase()+className.substring(1);
Object bean = getBean(beanName);
String fieldName = declaredField.getName();
String methodName = "set"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1);
Method method = null;
method = beanClass.getMethod(methodName, declaredField.getType());
Object object = getBean(next.getBeanName());
method.invoke(object, bean);
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
}
}
}
public void createObject( Set<MyBeanDefinition> set){
Iterator<MyBeanDefinition> iterator = set.iterator();
while(iterator.hasNext()){
MyBeanDefinition next = iterator.next();
Class beanClass = next.getBeanClass();
String beanName = next.getBeanName();
try {
//根据findBeanDefinitions里面存入的 class对象来新建一个对象
Object o = beanClass.newInstance();
Field[] declaredFields = beanClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
myValue myValueAnnotation = declaredField.getAnnotation(myValue.class);
if (myValueAnnotation!=null){
String value = myValueAnnotation.value();//获取value上面的值
String name = declaredField.getName();//获取方法名字
String methodName = "set"+name.substring(0, 1).toUpperCase()+name.substring(1);
try {
//获取get方法
System.out.println(methodName);
Method method = beanClass.getMethod(methodName,declaredField.getType());
try {
//完成数据类型转换
Object val = null;
switch (declaredField.getType().getName()){
case "java.lang.Integer":
val = Integer.parseInt(value);
break;
case "java.lang.String":
val = value;
break;
case "java.lang.Float":
val = Float.parseFloat(value);
break;
} //使用 set方法
method.invoke(o,val);
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
System.out.println(declaredField);
}
map.put(beanName,o);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
public Set<MyBeanDefinition> findBeanDefinitions(String pack){
Set<MyBeanDefinition> myset=new HashSet<>();
//获取到包下所有的类
Set<Class<?>> classes = MyTools.getClasses(pack);
Iterator<Class<?>> iterator = classes.iterator();
while(iterator.hasNext()){
Class<?> next = iterator.next();
myComponent annotation = next.getAnnotation( myComponent.class);
if(annotation != null){
String packname = next.getPackage().getName();
String name = next.getName();
String beanName = annotation.value();
if("".equals(beanName)){
String classname = name.replace(packname + ".", "");
String s = classname.substring(0, 1).toLowerCase();
beanName=s+classname.substring(1);
}
myset.add(new MyBeanDefinition(beanName,next));
}
}
return myset;
}
}
MyTools工具类
这个工具类做的主要是遍历指定的包 然后获取包里面的class
我的建议是 CV
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class MyTools {
public static Set<Class<?>> getClasses(String pack) {
// 第一个class类的集合
Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
// 是否循环迭代
boolean recursive = true;
// 获取包的名字 并进行替换
String packageName = pack;
String packageDirName = packageName.replace('.', '/');
// 定义一个枚举的集合 并进行循环来处理这个目录下的things
Enumeration<URL> dirs;
try {
dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
// 循环迭代下去
while (dirs.hasMoreElements()) {
// 获取下一个元素
URL url = dirs.nextElement();
// 得到协议的名称
String protocol = url.getProtocol();
// 如果是以文件的形式保存在服务器上
if ("file".equals(protocol)) {
// 获取包的物理路径
String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
// 以文件的方式扫描整个包下的文件 并添加到集合中
findClassesInPackageByFile(packageName, filePath, recursive, classes);
} else if ("jar".equals(protocol)) {
// 如果是jar包文件
// 定义一个JarFile
System.out.println("jar类型的扫描");
JarFile jar;
try {
// 获取jar
jar = ((JarURLConnection) url.openConnection()).getJarFile();
// 从此jar包 得到一个枚举类
Enumeration<JarEntry> entries = jar.entries();
findClassesInPackageByJar(packageName, entries, packageDirName, recursive, classes);
} catch (IOException e) {
// log.error("在扫描用户定义视图时从jar包获取文件出错");
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return classes;
}
private static void findClassesInPackageByJar(String packageName, Enumeration<JarEntry> entries, String packageDirName, final boolean recursive, Set<Class<?>> classes) {
// 同样的进行循环迭代
while (entries.hasMoreElements()) {
// 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
JarEntry entry = entries.nextElement();
String name = entry.getName();
// 如果是以/开头的
if (name.charAt(0) == '/') {
// 获取后面的字符串
name = name.substring(1);
}
// 如果前半部分和定义的包名相同
if (name.startsWith(packageDirName)) {
int idx = name.lastIndexOf('/');
// 如果以"/"结尾 是一个包
if (idx != -1) {
// 获取包名 把"/"替换成"."
packageName = name.substring(0, idx).replace('/', '.');
}
// 如果可以迭代下去 并且是一个包
if ((idx != -1) || recursive) {
// 如果是一个.class文件 而且不是目录
if (name.endsWith(".class") && !entry.isDirectory()) {
// 去掉后面的".class" 获取真正的类名
String className = name.substring(packageName.length() + 1, name.length() - 6);
try {
// 添加到classes
classes.add(Class.forName(packageName + '.' + className));
} catch (ClassNotFoundException e) {
// .error("添加用户自定义视图类错误 找不到此类的.class文件");
e.printStackTrace();
}
}
}
}
}
}
private static void findClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, Set<Class<?>> classes) {
// 获取此包的目录 建立一个File
File dir = new File(packagePath);
// 如果不存在或者 也不是目录就直接返回
if (!dir.exists() || !dir.isDirectory()) {
// log.warn("用户定义包名 " + packageName + " 下没有任何文件");
return;
}
// 如果存在 就获取包下的所有文件 包括目录
File[] dirfiles = dir.listFiles(new FileFilter() {
// 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
@Override
public boolean accept(File file) {
return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
}
});
// 循环所有文件
for (File file : dirfiles) {
// 如果是目录 则继续扫描
if (file.isDirectory()) {
findClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
} else {
// 如果是java类文件 去掉后面的.class 只留下类名
String className = file.getName().substring(0, file.getName().length() - 6);
try {
// 添加到集合中去
// classes.add(Class.forName(packageName + '.' +
// className));
// 经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净
classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
} catch (ClassNotFoundException e) {
// log.error("添加用户自定义视图类错误 找不到此类的.class文件");
e.printStackTrace();
}
}
}
}
}
测试方法
public class run {
public static void main(String[] args) {
MyAnnotationConfigApplicationContext myAnnotationConfigApplicationContext = new MyAnnotationConfigApplicationContext("myioc.test");
Object student = myAnnotationConfigApplicationContext.getBean("student");
System.out.println(student.toString());
Object at = myAnnotationConfigApplicationContext.getBean("at");
At a=(At)at;
System.out.println("================");
System.out.println(a.student.toString());
}
}
@myComponent()
public class At {
@myAutowired
@myQualifier("student")
public Student student;
@Override
public String toString() {
return "At{" +
"student=" + student +
'}';
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public At() {
}
public At(Student student) {
this.student = student;
}
}
package myioc.test;
import myioc.myAnnotation. myComponent;
import myioc.myAnnotation.myValue;
@myComponent()
public class Student {
@myValue("张三")
String name;
@myValue("25")
Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}