用反射模拟SpringIOC
1.代码结构

2. 基础类代码
MyComponent 自定义的组件注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyComponent {
}
MyComponentScan 自定义的扫描注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyComponentScan {
String[] value();
}
MyResource 自定义的Resource注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyResource {
}
User 类
public class User {
private String userName;
private String password;
public User(String userName, String password) {
this.userName = userName;
this.password = password;
}
...省略get、set
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", password='" + password + '\'' +
'}';
}
}
UserDao
public interface UserDao {
void login(User user);
}
UserDaoImpl 类
@MyComponent
public class UserDaoImpl implements UserDao {
@Override
public void login(User user) {
System.out.println("用户登录校验!");
}
}
UserService 类
public interface UserService {
void login(User user);
}
UserServiceImpl 类
@MyComponent
public class UserServiceImpl implements UserService {
@MyResource
private UserDao userDao;
@Override
public void login(User user) {
System.out.println("调用UserDaoImpl的login方法");
userDao.login(user);
}
}
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="user" class="com.xuboming.reflection.entity.User">
<property name="username" value="张三" />
<property name="password" value="123" />
</bean>
</beans>
3.核心代码
AnnotationConfigApplicationContext 对扫描路径下的类以及类中带MyResource注解的属性进行注入
/**
* 解析扫面路径下的类并解析类中的注解
*/
public class AnnotationConfigApplicationContext<T> {
//Class的存储路径
private String path;
//1.定义一个集合用来存在解析出来的对象,模拟spring容器
private Map<Class,Object> beanFactory = new HashMap<Class, Object>();
//2.从beanFactory中获取bean
public T getBean(Class clazz){
return (T) beanFactory.get(clazz);
}
//3.解析扫面路径下的类并解析类中的注解
public void initBeanByAnnotation(){
//编译后的项目根目录:E:/workspace/spring-study/spring-poxy/target/classes/
path = AnnotationConfigApplicationContext.class.getClassLoader().getResource("").getFile();
//3.1获取驱动类的class对象
Class clazz = MyTest.class;
//3.2获取扫描的注解
MyComponentScan myComponentScan = (MyComponentScan) clazz.getAnnotation(MyComponentScan.class);
if(myComponentScan != null){
//获取自定义的扫描路径
String[] scanPaths = myComponentScan.value();
//有定义扫描路径,就去加载路径下的实例
if(scanPaths != null && scanPaths.length>0){
loadClassInDefinedDir(path,scanPaths);
}
}
//对MyResource注解的属性进行注入
assembleObject();
}
//将扫描路径(相对路径)转为绝对路径,得到的是文件夹
private void loadClassInDefinedDir(String path,String[] scanPaths){
for(String scanPath : scanPaths){
scanPath = scanPath.replaceAll("\\.","/");
String fileDir = path + scanPath;
System.out.println(fileDir);
findClassFile(new File(fileDir));
}
}
//遍历文件夹,获取文件夹中的class文件
private void findClassFile(File fileDir) {
//判断路径是否为文件夹
if(fileDir.isDirectory()){
File[] files = fileDir.listFiles();
if(files == null || files.length == 0){
return ;
}
//遍历文件夹中的文件或文件夹
for(File file : files){
if(file.isDirectory()){//如果是文件夹,递归
findClassFile(file);
}else{//如果是文件,加载该类到容器中
loadClassWithAnnotation(file);
}
}
}
}
//将class文件转为对象,并存到beanFactory中
private void loadClassWithAnnotation(File file) {
//1.去掉前面的项目绝对路径
String classPath = file.getAbsolutePath().substring(path.length()-1);
//2.将'\'转为'.' 并去掉后面的'.class'
if(classPath.contains(".class")){
String fullName = classPath.replaceAll("\\\\","\\.").replaceAll("\\.class","");
try {
//获取Class对象
Class clazz = Class.forName(fullName);
//3.判断是不是接口,不是接口才创建实例
if(!clazz.isInterface()){
//4.判断是否有MyComponent注解,有MyComponent注解才创建对象
MyComponent myComponent = (MyComponent) clazz.getAnnotation(MyComponent.class);
if(myComponent != null ){
//5.创建实例
Object instance = clazz.newInstance();
//6.判断该类是否有实现的接口
Class[] interfaces = clazz.getInterfaces();
if(interfaces != null && interfaces.length>0){
//如果存在实现接口,将接口作为key,实例对象作为value存到map容器中 一个类只能实现一个接口,不用遍历接口类
System.out.println("正在加载类【"+interfaces[0].getName()+"】实例对象"+instance.getClass().getName());
//生成的对象加到beanFactory中
beanFactory.put(interfaces[0],instance);
}else{
//如果没有实现接口,就将class作为key,instance作为value
System.out.println("正在加载类【"+clazz.getName()+"】实例对象"+instance.getClass().getName());
//生成的对象加到beanFactory中
beanFactory.put(clazz,instance);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//给MyResource注解的属性赋值
private void assembleObject() {
//生成Map遍历器
Set<Map.Entry<Class, Object>> beanSet = beanFactory.entrySet();
//遍历所有遍历器中的Bean
for(Map.Entry<Class,Object> entry : beanSet){
//获取当前对象
Object object = entry.getValue();
//取当前对象的所有的属性值
Field[] fields = object.getClass().getDeclaredFields();
//遍历属性值判段是否存在MyResource注解
for(Field field : fields){
MyResource myResource = field.getAnnotation(MyResource.class);
//存在MyResource注解,给该属性赋值
if(myResource != null){
//打开安全检测机制
field.setAccessible(true);
try {
//给object(当前)对象中的属性赋值
field.set(object,beanFactory.get(field.getType()));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
}
ClassPathXMLApplicationContext 解析xml文件,将xml中的bean实例化
/**
* 解析xml文件
*/
public class ClassPathXMLApplicationContext {
//xml文件
private File file;
//模拟容器
private Map<String,Object> beanFactory = new HashMap();
//获取对象
public Object getBean(String id){
return beanFactory.get(id);
}
//构造方法,传入需要解析的xml文件名
public ClassPathXMLApplicationContext(String configXml) throws URISyntaxException {
//获取传入的xml文件的绝对路径
URL url = this.getClass().getClassLoader().getResource(configXml);
System.out.println(url.toURI());
//生成File
file = new File(url.toURI());
try {
//解析XMl
XMLParsing();
} catch (Exception e) {
e.printStackTrace();
}
}
//解析Xml
private void XMLParsing() throws JDOMException, IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
SAXBuilder builder = new SAXBuilder();
Document document = builder.build(file);
//获取根节点
Element root = document.getRootElement();
//获取所有的bean节点
List beanElementList = root.getChildren("bean");
//生成bean节点集合的遍历器
Iterator it = beanElementList.iterator();
//遍历bean节点
while (it.hasNext()){
Element bean = (Element) it.next();
//获取id属性值
String id = bean.getAttributeValue("id");
//获取class属性值
String cls = bean.getAttributeValue("class");
//根据class创建class对象
Class clazz = Class.forName(cls);
//实例化
Object object = clazz.newInstance();
//获取类中所有的方法
Method[] methods = clazz.getDeclaredMethods();
//获取bean下的property节点集合
List<Element> propertyElementList = bean.getChildren("property");
//判断property是否为空,methods是否为空。一般都不会为空
if(propertyElementList != null && propertyElementList.size()>0 && methods != null && methods.length>0){
//给property中的属性赋值
for(Element property : propertyElementList){
//获取属性名
String name = property.getAttributeValue("name");
//获取属性值
String value = property.getAttributeValue("value");
//遍历该对象下的所有方法
for(Method method : methods){
//获得方法名
String methodName = method.getName();
//判断该方法是否是set方法
if(methodName.startsWith("set")){
//如果是set方法,将其处理后与property中进行比较判断是否相等
methodName = methodName.substring(3).toLowerCase();
if(methodName.equals(name)){
//如果相等,调用该方法对对象Object进行赋值
method.invoke(object,value);
}
}
}
}
}
beanFactory.put(id,object);
}
}
}
4. 运行结果
MyTest 客户端
@MyComponentScan({"com.xuboming.reflection.dao","com.xuboming.reflection.service"})
public class MyTest {
public static void main(String[] args) throws URISyntaxException {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.initBeanByAnnotation();
UserServiceImpl userService = (UserServiceImpl) applicationContext.getBean(UserService.class);
ClassPathXMLApplicationContext classPathXMLApplicationContext = new ClassPathXMLApplicationContext("beans.xml");
User user = (User) classPathXMLApplicationContext.getBean("user");
System.out.println(user);
userService.login(user);
}
}
运行结果


浙公网安备 33010602011771号