使用Java反射模拟实现Spring的IoC容器的操作

网友投稿 213 2022-10-05


使用Java反射模拟实现Spring的IoC容器的操作

目录实现的功能:项目结构下面是程序的项目结构图:自定义注解容器实现测试实体类User的定义:

实现的功能:

默认情况下将扫描整个项目的文件

可以使用@ComponentScan注解配置扫描路径

只将被@Component注解修饰的类装载到容器中

可以使用@AutoWired注解实现自动装配

读取配置文件中的声明的类并注册到容器中

项目结构

下面是程序的项目结构图:

自定义注解

下面是自定义的三个注解: @AutoWired,@Component,@ComponentScan。

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface AutoWired {

}

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public @interface Component {

}

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public @interface ComponentScan {

String[] value();

}

容器实现

其中AnnotationConfigApplicationContext和ClassPathXMLApplicationContext为核心的类,其中

AnnotationConfigApplicationContext类实现扫描文件和解析注解等功能。

package learn.reflection.reflect;

import learn.reflection.Bootstrap;

import learn.reflection.annotation.AutoWired;

import learn.reflection.annotation.Component;

import learn.reflection.annotation.ComponentScan;

import java.io.File;

import java.io.InputStream;

import java.lang.reflect.Field;

import java.util.HashMap;

import java.util.Map;

import java.util.Properties;

import java.util.Set;

public class AnnotationConfigApplicationContext{

//使用HaspMap存储Bean

private HashMap beanFactory=new HashMap<>();

//获取Bean的方法

public T getBean(Class clazz){

return (T) beanFactory.get(clazz);

}

String path;//编译后的字节码存储路径

/**

* 初始化ApplicationContext,加载注解修饰的Bean到beanFactory

*/

public void initContextByAnnotation(){

//编译后的项目根目录:D:/idea_workplace/javaAppliTechnology/target/classes/

path = AnnotationConfigApplicationContext.class.getClassLoader().getResource("").getFile();

//查看启动类Bootstrap是否有定义扫描包

ComponentScan annotation = Bootstrap.class.getAnnotation(ComponentScan.class);

if (annotation!=null){

//有定义就只扫描自定义的

String[] definedPaths = annotation.value();

if (definedPaths!=null&&definedPaths.length>0){

loadClassInDefinedDir(path,definedPaths);

}

}else{

//默认扫描整个项目的目录

System.out.println(path);

findClassFile(new File(path));

}

assembleObject();

}

/**

* 给@AutoWired修饰的属性赋值

*/

private void assembleObject(){

Set> entries = beanFactory.entrySet();

//扫描所有容器中的Bean

for (Map.Entry entry : entries) {

Object value = entry.getValue();

//获取所有属性

Field[] fields = value.getClass().getDeclaredFields();

for (Field field : fields) {

//如果被@AutoWired注解修饰则进行赋值

AutoWired annotation = field.getAnnotation(AutoWired.class);

if (annotation!=null){

try {

field.setAccessible(true);

field.set(value,beanFactory.get(field.getType()));

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}

}

}

}

/**

* 扫描用户自定义的包

* @param path

* @param definedPaths

*/

private void loadClassInDefinedDir(String path, String[] definedPaths){

for (String definedPath : definedPaths) {

//转换成绝对路径

String s = definedPath.replaceAll("\\.", "/");

String fullName=path+s;

System.out.println(s);

findClassFile(new File(fullName));

}

}

/**

* 扫描项目中的每一个文件夹找到所有的class文件

*/

private void findClassFile(File pathParent) {

//路径是否是目录,子目录是否为空

if (pathParent.isDirectory()) {

File[] childrenFiles = pathParent.listFiles();

if (childrenFiles == null || childrenFiles.length == 0) {

return;

}

for (File childrenFile : childrenFiles) {

if (childrenFile.isDirectory()) {

//递归调用直到找到所有的文件

findClassFile(childrenFile);

} else {

//找到文件

loadClassWithAnnotation(childrenFile);

}

}

}

}

/**

* 装配找到的所有带有@Component注解的类到容器

*/

private void loadClassWithAnnotation(File file) {

//1.去掉前面的项目绝对路径

String pathWithClass=file.getAbsolutePath().substring(path.length()-1);

//2.将路径的“/”转化为“.”和去掉后面的.class

if (pathWithClass.contains(".class")){

String fullName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");

/**

* 根据获取到的类的全限定名使用反射将实例添加到beanFactory中

*/

try {

Class> clazz = Class.forName(fullName);

//3.判断是不是接口,不是接口才创建实例

if (!clazz.isInterface()){

//4.是否具有@Bean注解

Component annotation = clazz.getAnnotation(Component.class);

if (annotation!=null){

//5.创建实例对象

Object instance = clazz.newInstance();

//6.判断是否有实现的接口

Class>[] interfaces = clazz.getInterfaces();

if (interfaces!=null&&interfaces.length>0){

//如果是有接口就将其接口的class作为key,实例对象作为value

System.out.println("正在加载【"+interfaces[0].getName()+"】 实例对象:"+instance.getClass().getName());

beanFactory.put(interfaces[0],instance);

}else{

System.out.println("正在加载【"+clazz.getName()+"】 实例对象:"+instance.getClass().getName());

beanFactory.put(clazz,instance);

}

//如果没有接口就将自己的class作为key,实例对象作为value

}

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

}

ClassPathXMLApplicationContext类实现解析xml配置文件,并装载组件到容器中。

package learn.reflection.reflect;

import java.net.URL;

import java.util.HashMap;

import java.util.Map;

import org.jdom2.Document;

import org.jdom2.JDOMException;

import org.jdom2.Element;

import org.jdom2.xpath.XPath;

import org.jdom2.input.SAXBuilder;

import java.io.File;

import java.io.IOException;

import java.net.URL;

import java.net.URISyntaxException;

import java.util.*;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

import java.lang.reflect.InvocationTargetException;

/**

* @author Hai

* @date 2020/5/17 - 18:47

*/

public class ClassPathXMLApplicationContext{

private File file;

private Map map = new HashMap();

public ClassPathXMLApplicationContext(String config_file) {

URL url = this.getClass().getClassLoader().getResource(config_file);

try {

file = new File(url.toURI());

XMLParsing();

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

private void XMLParsing() throws Exception {

SAXBuilder builder = new SAXBuilder();

Document document = builder.build(file);

Element root = document.getRootElement();

List elementList = root.getChildren("bean");

Iterator i = elementList.iterator();

//读取bean节点的所有信息

while (i.hasNext()) {

Element bean = (Element) i.next();

String id = bean.getAttributeValue("id");

//根据class创建实例

String cls = bean.getAttributeValue("class");

Object obj = Class.forName(cls).newInstance();

Method[] method = obj.getClass().getDeclaredMethods();

List list = bean.getChildren("property");

for (Element el : list) {

for (int n = 0; n < method.length; n++) {

String name = method[n].getName();

String temp = null;

//找到属性对应的setter方法进行赋值

if (name.startsWith("set")) {

temp = name.substring(3, name.length()).toLowerCase();

if (el.getAttribute("name") != null) {

if (temp.equals(el.getAttribute("name").getValue())) {

method[n].invoke(obj, el.getAttribute("value").getValue());

}

}

}

}

}

map.put(id, obj);

}

}

public Object getBean(String name) {

return map.get(name);

}

}

测试

实体类User的定义:

@Component

public class User {

private String username;

private String password;

public User(String username, String password) {

this.username = username;

this.password = password;

}

public User() {

}

//省略getter,setter方法

}

在UserServiceImpl类中添加@Component注解,并使用@AutoWired注解注入容器中的IUerDao接口的实现类UserDaoImpl。

@Component

public class UserServiceImpl implements IUserService {

@AutoWired

private IUserDao userDao;

@Override

public void login(User user) {

System.out.println("调用UserDaoImpl的login方法");

userDao.loginByUsername(user);

}

}

UserDaoImpl类同样添加@Component注解

@Component

public class UserDaoImpl implements IUserDao {

@Override

public void loginByUsername(User user) {

System.out.println("验证用户http://【"+user.getUsername()+"】登录");

}

}

在beans.xml中配置注册User类,文件beans.xml的内容如下:

下面同时使用 AnnotationConfigApplicationContext类和 ClassPathXMLApplicationContext类。

Bootstrap类作为启动类添加注解@ComponentScan,指定扫描learn.reflection.dao和learn.reflection.service这两个包。

@ComponentScan(value = {"learn.reflection.dao","learn.reflection.service"})

public class Bootstrap {

public static void main(String[] args) {

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

applicationContext.initContextByAnnotation();

UserServiceImpl userService = (UserServiceImpl) applicationContext.getBean(IUserService.class);

ClassPathXMLApplicationContext xmlApplicationContext = new ClassPathXMLApplicationContext("beans.xml");

User user = (User) xmlApplicationContext.getBean("user");

System.out.println(user);

userService.login(user);

}

}

运行Bootstrap类,程序运行结果如下:

learn/reflection/dao

正在加载【learn.reflection.dao.IUserDao】 实例对象:learn.reflection.dao.impl.UserDaoImpl

learn/reflection/service

正在加载【learn.reflection.service.IUserService】 实例对象:learn.reflection.service.impl.UserServiceImpl

User{username='张三', password='123'}

调用UserDaoImpl的login方法

验证用户【张三】登录


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:中睿天下完成数亿元C轮融资(中睿天下 融资)
下一篇:产业园多功能仪表能耗监测系统的设计与应用
相关文章

 发表评论

暂时没有评论,来抢沙发吧~