Spring框架的IOC是基于Java反射机制实现的,那具体怎么实现的,下面研究一下
Java
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java
语言的反射机制。简单来说,反射机制指的是程序在运行时能够获取自身的信息。
要想解剖一个类,必须先要获取到该类的Class对象。而剖析一个类或用反射解决具体的问题就是使用相关API**(1)java.lang.Class(2)java.lang.reflect**,所以,Class对象是反射的根源。
package com.atguigu.reflect;
public class Car {
//属性
private String name;
private int age;
private String color;
//无参数构造
public Car() {
}
//有参数构造
public Car(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
//普通方法
private void run() {
System.out.println("私有方法-run.....");
}
//get和set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", age=" + age +
", color='" + color + '\'' +
'}';
}
}
package com.atguigu.reflect;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class TestCar {
//1、获取Class对象多种方式
@Test
public void test01() throws Exception {
//1 类名.class
Class clazz1 = Car.class;
//2 对象.getClass()
Class clazz2 = new Car().getClass();
//3 Class.forName("全路径")
Class clazz3 = Class.forName("com.atguigu.reflect.Car");
//实例化
Car car = (Car)clazz3.getConstructor().newInstance();
System.out.println(car);
}
}
package com.atguigu.reflect;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class TestCar {
//1、获取Class对象多种方式
@Test
public void test01() throws Exception {
//1 类名.class
Class clazz1 = Car.class;
//2 对象.getClass()
Class clazz2 = new Car().getClass();
//3 Class.forName("全路径")
Class clazz3 = Class.forName("com.atguigu.reflect.Car");
int length = clazz1.getInterfaces().length;
System.out.println(length);
//实例化
Car car = (Car)clazz3.getConstructor().newInstance();
System.out.println(car);
}
//2、获取构造方法
@Test
public void test02() throws Exception {
Class clazz = Car.class;
//获取所有构造
// getConstructors()获取所有public的构造方法
// Constructor[] constructors = clazz.getConstructors();
//getDeclaredConstructors()获取所有的构造方法public private
// Constructor[] constructors = clazz.getDeclaredConstructors();
// for (Constructor c:constructors) {
// System.out.println("方法名称:"+c.getName()+" 参数个数:"+c.getParameterCount());
// }
//指定有参数构造创建对象
//1 构造public
// Constructor c1 = clazz.getConstructor(String.class, int.class, String.class);
// Car car1 = (Car)c1.newInstance("夏利", 10, "红色");
// System.out.println(car1);
//2 构造private
Constructor c2 = clazz.getDeclaredConstructor(String.class, int.class, String.class);
c2.setAccessible(true);
Car car2 = (Car)c2.newInstance("捷达", 15, "白色");
System.out.println(car2);
}
//3、获取属性
@Test
public void test03() throws Exception {
Class clazz = Car.class;
Car car = (Car)clazz.getDeclaredConstructor().newInstance();
//获取所有public属性
//Field[] fields = clazz.getFields();
//获取所有属性(包含私有属性)
Field[] fields = clazz.getDeclaredFields();
for (Field field:fields) {
if(field.getName().equals("name")) {
//设置允许访问
field.setAccessible(true);
field.set(car,"五菱宏光");
System.out.println(car);
}
System.out.println(field.getName());
}
}
//4、获取方法
@Test
public void test04() throws Exception {
Car car = new Car("奔驰",10,"黑色");
Class clazz = car.getClass();
//1 public方法
Method[] methods = clazz.getMethods();
for (Method m1:methods) {
//System.out.println(m1.getName());
//执行方法 toString
if(m1.getName().equals("toString")) {
String invoke = (String)m1.invoke(car);
//System.out.println("toString执行了:"+invoke);
}
}
//2 private方法
Method[] methodsAll = clazz.getDeclaredMethods();
for (Method m:methodsAll) {
//执行方法 run
if(m.getName().equals("run")) {
m.setAccessible(true);
m.invoke(car);
}
}
}
}
package com.atguigu.service;
public interface UserService {
void add();
}
package com.atguigu.service.impl;
import com.atguigu.service.UserService;
public class UserServiceImpl implements UserService {
@Di
private UserDao userDao;
public void add() {
System.out.println("service.......");
//调用dao的方法
userDao.add();
}
}
package com.atguigu.dao;
public interface UserDao {
void add();
}
package com.atguigu.dao.impl;
import com.atguigu.anno.Bean;
import com.atguigu.dao.UserDao;
import org.springframework.stereotype.Repository;
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("dao.......");
}
}
package com.atguigu.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
}
package com.atguigu.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Di {
}
package com.atguigu.bean;
public interface ApplicationContext {
Object getBean(Class clazz);
}
package com.atguigu.bean;
import com.atguigu.anno.Bean;
import com.atguigu.anno.Di;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class AnnotationApplicationContext implements ApplicationContext{
//创建map集合,放bean对象
private Map beanFactory = new HashMap<>();
private static String rootPath;
//返回对象
@Override
public Object getBean(Class clazz) {
return beanFactory.get(clazz);
}
//创建有参数构造,传递包路径,设置包扫描规则
//当前包及其子包,哪个类有@Bean注解,把这个类通过反射实例化
public AnnotationApplicationContext(String basePackage) {
// com.atguigu
try {
//1 把.替换成\
String packagePath = basePackage.replaceAll("\\.",
"\\\\");
//2 获取包绝对路径
Enumeration urls
= Thread.currentThread().getContextClassLoader()
.getResources(packagePath);
while(urls.hasMoreElements()) {
URL url = urls.nextElement();
String filePath = URLDecoder.decode(url.getFile(),
"utf-8");
//获取包前面路径部分,字符串截取
rootPath = filePath.substring(0, filePath.length() - packagePath.length());
//包扫描
loadBean(new File(filePath));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
//属性注入
loadDi();
}
//包扫描过程,实例化
private void loadBean(File file) throws Exception {
//1 判断当前是否文件夹
if(file.isDirectory()) {
//2 获取文件夹里面所有内容
File[] childrenFiles = file.listFiles();
//3 判断文件夹里面为空,直接返回
if(childrenFiles == null || childrenFiles.length == 0) {
return;
}
//4 如果文件夹里面不为空,遍历文件夹所有内容
for(File child : childrenFiles) {
//4.1 遍历得到每个File对象,继续判断,如果还是文件夹,递归
if(child.isDirectory()) {
//递归
loadBean(child);
} else {
//4.2 遍历得到File对象不是文件夹,是文件,
//4.3 得到包路径+类名称部分-字符串截取
String pathWithClass =
child.getAbsolutePath().substring(rootPath.length() - 1);
//4.4 判断当前文件类型是否.class
if(pathWithClass.contains(".class")) {
//4.5 如果是.class类型,把路径\替换成. 把.class去掉
// com.atguigu.service.UserServiceImpl
String allName = pathWithClass.replaceAll("\\\\", ".")
.replace(".class", "");
//4.6 判断类上面是否有注解 @Bean,如果有实例化过程
//4.6.1 获取类的Class
Class> clazz = Class.forName(allName);
//4.6.2 判断不是接口
if(!clazz.isInterface()) {
//4.6.3 判断类上面是否有注解 @Bean
Bean annotation = clazz.getAnnotation(Bean.class);
if(annotation != null) {
//4.6.4 实例化
Object instance = clazz.getConstructor().newInstance();
//4.7 把对象实例化之后,放到map集合beanFactory
//4.7.1 判断当前类如果有接口,让接口class作为map的key
if(clazz.getInterfaces().length>0) {
beanFactory.put(clazz.getInterfaces()[0],instance);
} else {
beanFactory.put(clazz,instance);
}
}
}
}
}
}
}
}
//属性注入
private void loadDi() {
//实例化对象在beanFactory的map集合里面
//1 遍历beanFactory的map集合
Set> entries = beanFactory.entrySet();
for (Map.Entry entry:entries) {
//2 获取map集合每个对象(value),每个对象属性获取到
Object obj = entry.getValue();
//获取对象Class
Class> clazz = obj.getClass();
//获取每个对象属性获取到
Field[] declaredFields = clazz.getDeclaredFields();
//3 遍历得到每个对象属性数组,得到每个属性
for(Field field:declaredFields) {
//4 判断属性上面是否有@Di注解
Di annotation = field.getAnnotation(Di.class);
if(annotation != null) {
//如果私有属性,设置可以设置值
field.setAccessible(true);
//5 如果有@Di注解,把对象进行设置(注入)
try {
field.set(obj,beanFactory.get(field.getType()));
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
}
}
最终测试
package com.atguigu;
import com.atguigu.bean.AnnotationApplicationContext;
import com.atguigu.bean.ApplicationContext;
import com.atguigu.service.UserService;
public class TestUser {
public static void main(String[] args) {
ApplicationContext context =
new AnnotationApplicationContext("com.atguigu");
UserService userService = (UserService)context.getBean(UserService.class);
System.out.println(userService);
userService.add();
}
}