SpringIOC随笔(二)-仿写SpringIOC

it2023-08-18  61

SpringIOC随笔(二)-仿写SpringIOC

思路:

定义一个beanFactor工厂接口,提供getBean方法,实现工厂,定义一个Bean容器,Map,为了实现线程安全,使用private static Map<String, Object> beanMap = Collections.synchronizedMap(new HashMap<>());初始化我们的bean容器,通过解析我们的xml配置文件//beans/bean创建出bean初始化完成bean容器后我们需要将bean之间的关系装配好(注入)然后实现getBean方法。

使用技术:dom4j解析xml,反射

代码:

pom

<dependencies> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>jaxen</groupId> <artifactId>jaxen</artifactId> <version>1.1.6</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.4</version> </dependency> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.2.1</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>

applicationContext.xml

<?xml version="1.0" encoding="UTF-8" ?> <beans> <bean id="userDaoHibernate" class="com.fxyh.spring.dao.impl.UserDaoHibernateImpl" /> <bean id="userDaoMybatis" class="com.fxyh.spring.dao.impl.UserDaoMybatisImpl"/> <bean id="userService" class="com.fxyh.spring.service.impl.UserServiceImpl"> <property name="userDao" ref="userDaoMybatis" /> </bean> </beans>

Dom4jUtils

public class Dom4jUtils { /** * @Author fengzhaoquan * @Description 获取XML文档。其实就是将xml文档读取到内存中,形成DOM树 * @Date * @Param * @return **/ public static Document getDocument(String fileName){ Document document = null; if(StringUtils.isBlank(fileName)){ throw new IllegalArgumentException(""); } try { SAXReader reader = new SAXReader(); document = reader.read(Dom4jUtils.class.getClassLoader().getResourceAsStream(fileName)); } catch (DocumentException e) { e.printStackTrace(); } return document; } }

BeanFactory接口

public interface BeanFactory { /** * @Author fengzhaoquan * @Description 实现了该接口类型的对象 * @Param clazz 接口类型的对象 **/ Object getBean(Class clazz); /** * @Author fengzhaoquan * @Description 获取className的对象(id) **/ Object getBean(String className); }

ClassPathXmlApplicationContext实现BeanFactory接口

/** * @ClassName: ClassPathXmlApplicationContext * @description: BeanFactory的一个实现类 * 1. 将xml中所有的bean标签创建出对象,然后放入容器中 * 2. 对外提供了getBean方法,从而对于客户端而言可以很轻松的获取对象 * @author: fengzhaoquan * @create: 2019-06-16 16:44 * @Version 1.0 **/ public class ClassPathXmlApplicationContext implements BeanFactory { /** * @Author fengzhaoquan * @Description 配置文件中所有的bean都会放入beanMap中 **/ private static Map<String, Object> beanMap = Collections.synchronizedMap(new HashMap<>()); public ClassPathXmlApplicationContext() { this("applicationContext.xml"); } public ClassPathXmlApplicationContext(String fileName) { if (StringUtils.isBlank(fileName)) { throw new IllegalArgumentException(""); } try { // 解析XML // 初始化beanMap initBeanMap(fileName); // 将bean之间的关系装配好(注入) injection(fileName); } catch (Exception e) { e.printStackTrace(); } } /** * @Author fengzhaoquan * @Description 将bean之间的关系装配好(注入) **/ private void injection(String fileName) throws Exception { Document document = Dom4jUtils.getDocument(fileName); List<Element> propertyElementList = document.selectNodes("//beans/bean/property"); if (CollectionUtils.isNotEmpty(propertyElementList)) { for (Element propertyElement : propertyElementList) { String name = propertyElement.attributeValue("name"); String refValue = propertyElement.attributeValue("ref"); //setXxx方法拼接 String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1); //找到父元素,也是就要被注入的对象 Element beanElement = propertyElement.getParent(); String parentElementIdValue = beanElement.attributeValue("id"); if (beanMap.containsKey(parentElementIdValue) && beanMap.containsKey(refValue)){ Object targetObject = beanMap.get(parentElementIdValue); Object parameterValue = beanMap.get(refValue); Method method = targetObject.getClass().getDeclaredMethod(methodName, parameterValue.getClass().getInterfaces()); method.invoke(targetObject, parameterValue); } } } } /** * @Author fengzhaoquan * @Description 初始化beanMap **/ private void initBeanMap(String fileName) throws ClassNotFoundException, IllegalAccessException, InstantiationException { Document document = Dom4jUtils.getDocument(fileName); //XPath List<Element> beanElementList = document.selectNodes("//beans/bean"); if (CollectionUtils.isNotEmpty(beanElementList)) { for (Element beanElement : beanElementList) { String id = beanElement.attributeValue("id"); String beanClassName = beanElement.attributeValue("class"); beanMap.put(id, Class.forName(beanClassName).newInstance()); } } } @Override public Object getBean(Class clazz) { if(clazz == null){ throw new IllegalArgumentException(""); } return beanMap.get(clazz.getSimpleName().substring(0,1).toLowerCase() + clazz.getSimpleName().substring(1)); } @Override public Object getBean(String className) { if(StringUtils.isBlank(className)){ throw new IllegalArgumentException(""); } return beanMap.get(className); } }

Service,Dao,model代码:

public class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void addUser(User user) { userDao.addUser(user); } } public class UserDaoHibernateImpl implements UserDao { @Override public void addUser(User user) { System.out.println("Hibernate add:" + user); } } public class UserDaoMybatisImpl implements UserDao { @Override public void addUser(User user) { System.out.println("Mybatis add:" + user); } } public class User implements Serializable { private static final long serialVersionUID = -5333671573596770181L; private String name; private String password; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", password='" + password + '\'' + '}'; } }

单元测试

public class UserServiceImplTest { private BeanFactory factory; private UserService userService; @Before public void setUp() throws Exception { this.factory = new ClassPathXmlApplicationContext(); this.userService = (UserService) this.factory.getBean(UserService.class); } @Test public void addUser() { User user = new User(); user.setName("zhangsan"); user.setPassword("123456"); userService.addUser(user); } }

这是一个基本上可以说非常简陋的IOC,但是和Spring的原理是一样的。

最新回复(0)