假如你现在还在为自己的技术担忧,假如你现在想提升自己的工资,假如你想在职场上获得更多的话语权,假如你想顺利的度过35岁这个魔咒,假如你想体验BAT的工作环境,那么现在请我们一起开启提升技术之旅吧,详情请点击http://106.12.206.16:8080/qingruihappy/index.html
一,xml方式
注解方式就不写了,主要就是dom4j的解析。
二,注解方式
2.1,我们先来看一下spring自带的写法
spring.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- <bean id="userServiceImpl" class="com.qingruihappy2.utils.UserServiceImpl"></bean> --> <context:component-scan base-package="com.qingruihappy4" /> </beans>
package com.qingruihappy4.dao; import org.springframework.stereotype.Service; @Service public class OrderDao { public void addOrder() { System.out.println("我是OrderDao层,我在用@Service方法注入到容器中去。"); } }
package com.qingruihappy4.dao; import org.springframework.stereotype.Service; @Service public class UserDao { public void add() { System.out.println("我是UserDao层,我在用@Service方法注入到容器中去。"); } }
package com.qingruihappy4.service; public interface OrderService { public void addOrder(); }
package com.qingruihappy4.service.impl; import javax.annotation.Resource; import org.springframework.stereotype.Service; import com.qingruihappy4.dao.OrderDao; import com.qingruihappy4.service.OrderService; @Service public class OrderServiceImpl implements OrderService { // 从Spring容器中读取bean @Resource private OrderDao orderDao; public void addOrder() { orderDao.addOrder(); System.out.println("我是OrderServiceImpl,我在通过@Resource把orderDao取出来"); } }
package com.qingruihappy4.service; public interface OrderService { public void addOrder(); }
package com.qingruihappy4.service.impl; import javax.annotation.Resource; import org.springframework.stereotype.Service; import com.qingruihappy4.dao.OrderDao; import com.qingruihappy4.service.OrderService; @Service public class OrderServiceImpl implements OrderService { // 从Spring容器中读取bean @Resource private OrderDao orderDao; public void addOrder() { orderDao.addOrder(); System.out.println("我是OrderServiceImpl,我在通过@Resource把orderDao取出来"); } }
package com.qingruihappy4; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.qingruihappy4.service.OrderService; import com.qingruihappy4.service.UserService; public class Test001 { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("spring.xml"); //假如我们现在放到mvc的模式中,我们会发现启动的时候就会去加载spring的xml文件,去扫包。注意扫包的时候并没有把通过@Service往容器中放值 //启动的时候就会通过另一套机制加载发现有@Service注解,面向切面的思想,就会把它放到容器中去。 //当开始访问的时候就会通过@Resource注解,面向切面的思想就会从容器中去取对应的实例,没有就会报空指针异常 UserService userService = (UserService) app.getBean("userServiceImpl"); userService.add(); OrderService orderService = (OrderService) app.getBean("orderServiceImpl"); orderService.addOrder(); } }
2.2,手写
自定义注解
package com.qingruihappy3.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; //自定义注解 从Spring容器获取bean @Target({ ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) public @interface ExtResource { }
package com.qingruihappy3.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; // 自定义注解 注入到Spring容器 @Target({ ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) public @interface ExtService { }
扫包工具类这个不是重点,知道它能获取到规定package下面所有的class文件的类的实例就行了
package com.qingruihappy3.utils; 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.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; public class ClassUtil { /** * 取得某个接口下所有实现这个接口的类 */ public static List<Class> getAllClassByInterface(Class c) { List<Class> returnClassList = null; if (c.isInterface()) { // 获取当前的包名 String packageName = c.getPackage().getName(); // 获取当前包下以及子包下所以的类 List<Class<?>> allClass = getClasses(packageName); if (allClass != null) { returnClassList = new ArrayList<Class>(); for (Class classes : allClass) { // 判断是否是同一个接口 if (c.isAssignableFrom(classes)) { // 本身不加入进去 if (!c.equals(classes)) { returnClassList.add(classes); } } } } } return returnClassList; } /* * 取得某一类所在包的所有类名 不含迭代 */ public static String[] getPackageAllClassName(String classLocation, String packageName) { // 将packageName分解 String[] packagePathSplit = packageName.split("[.]"); String realClassLocation = classLocation; int packageLength = packagePathSplit.length; for (int i = 0; i < packageLength; i++) { realClassLocation = realClassLocation + File.separator + packagePathSplit[i]; } File packeageDir = new File(realClassLocation); if (packeageDir.isDirectory()) { String[] allClassName = packeageDir.list(); return allClassName; } return null; } /** * 从包package中获取所有的Class * * @param pack * @return */ public static List<Class<?>> getClasses(String packageName) { // 第一个class类的集合 List<Class<?>> classes = new ArrayList<Class<?>>(); // 是否循环迭代 boolean recursive = true; // 获取包的名字 并进行替换 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"); // 以文件的方式扫描整个包下的文件 并添加到集合中 findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes); } else if ("jar".equals(protocol)) { // 如果是jar包文件 // 定义一个JarFile JarFile jar; try { // 获取jar jar = ((JarURLConnection) url.openConnection()).getJarFile(); // 从此jar包 得到一个枚举类 Enumeration<JarEntry> entries = jar.entries(); // 同样的进行循环迭代 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) { e.printStackTrace(); } } } } } } catch (IOException e) { e.printStackTrace(); } } } } catch (IOException e) { e.printStackTrace(); } return classes; } /** * 以文件的形式来获取包下的所有Class * * @param packageName * @param packagePath * @param recursive * @param classes */ public static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, List<Class<?>> classes) { // 获取此包的目录 建立一个File File dir = new File(packagePath); // 如果不存在或者 也不是目录就直接返回 if (!dir.exists() || !dir.isDirectory()) { return; } // 如果存在 就获取包下的所有文件 包括目录 File[] dirfiles = dir.listFiles(new FileFilter() { // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件) public boolean accept(File file) { return (recursive && file.isDirectory()) || (file.getName().endsWith(".class")); } }); // 循环所有文件 for (File file : dirfiles) { // 如果是目录 则继续扫描 if (file.isDirectory()) { findAndAddClassesInPackageByFile(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)); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } } }
dao层
package com.qingruihappy3.dao; import com.qingruihappy3.annotation.ExtService; @ExtService public class OrderDao { public void addOrder() { System.out.println("我是OrderDao层,我在用@ExtService方法注入到容器中去。"); } }
package com.qingruihappy3.dao; import com.qingruihappy3.annotation.ExtService; @ExtService public class UserDao { public void add() { System.out.println("我是UserDao层,我在用@ExtService方法注入到容器中去。"); } }
service接口层
package com.qingruihappy3.service; public interface OrderService { public void addOrder(); }
package com.qingruihappy3.service; public interface UserService { public void add(); }
service实现层
package com.qingruihappy3.service.impl; import com.qingruihappy3.annotation.ExtResource; import com.qingruihappy3.annotation.ExtService; import com.qingruihappy3.dao.OrderDao; import com.qingruihappy3.service.OrderService; @ExtService public class OrderServiceImpl implements OrderService { // 从Spring容器中读取bean @ExtResource private OrderDao orderDao; public void addOrder() { orderDao.addOrder(); System.out.println("我是OrderServiceImpl,我在通过@ExtResource把orderDao取出来"); } }
package com.qingruihappy3.service.impl; import com.qingruihappy3.annotation.ExtResource; import com.qingruihappy3.annotation.ExtService; import com.qingruihappy3.dao.UserDao; import com.qingruihappy3.service.OrderService; import com.qingruihappy3.service.UserService; //将该类注入到spring容器里面 @ExtService public class UserServiceImpl implements UserService { // 从Spring容器中读取bean @ExtResource private UserDao userDao; public void add() { userDao.add(); System.out.println("我是UserServiceImpl,我在通过@ExtResource把UserDao取出来"); } }
重点来了
package com.qingruihappy3.spring; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.lang.StringUtils; import com.qingruihappy3.annotation.ExtResource; import com.qingruihappy3.annotation.ExtService; import com.qingruihappy3.utils.ClassUtil; /** * 手写Spring专题 注解版本注入bean * * @author 黄庆瑞 * */ @SuppressWarnings({ "rawtypes", "unchecked" }) public class ClassPathXmlApplicationContext { // 扫包范围 private String packageName; public ClassPathXmlApplicationContext(String packageName) { this.packageName = packageName; } // 把带有@service注解的对象放到map中去 public ConcurrentHashMap<String, Object> setMap() throws Exception { // 1.使用反射机制获取该包下所有的类已经存在bean的注解类,放到一个list集合中 List<Class> listClassesAnnotation = findClassExisService(); if (listClassesAnnotation == null || listClassesAnnotation.isEmpty()) { throw new Exception("没有需要初始化的bean"); } // 2.使用Java反射机制初始化对象,在放到一个map集合中,map的可以就是对象名称的首字母小写,value就是加注解的对象 ConcurrentHashMap<String, Object> initBean = initBean(listClassesAnnotation); if (initBean == null || initBean.isEmpty()) { throw new Exception("初始化bean为空!"); } return initBean; } // 使用beanID查找对象 public Object getBean(ConcurrentHashMap<String, Object> initBean,String beanId) throws Exception { // 3.使用beanID查找查找对应bean对象 Object object = initBean.get(beanId); // 4.使用反射读取类的属性,赋值信息,这里是有问题的。 attriAssign(initBean,object); return object; } // 使用反射读取类的属性,赋值信息 public void attriAssign(ConcurrentHashMap<String, Object> initBean,Object object) throws Exception { // 1.获取类的属性是否存在 获取bean注解 Class<? extends Object> classInfo = object.getClass(); Field[] declaredFields = classInfo.getDeclaredFields(); for (Field field : declaredFields) { ExtResource annotation = field.getAnnotation(ExtResource.class); if (annotation != null) { // 属性名称 String name = field.getName(); // 2.使用属性名称查找bean容器赋值 Object bean = initBean.get(name); if (bean != null) { // 私有访问允许访问 field.setAccessible(true); // 给属性赋值,给object(userserviceimpl)的属性field(userdao)赋值bean(从容器中拿到到userdao) field.set(object, bean); continue; } } else { throw new Exception("ExtResource没有注入到" + field.getName() + "方法上去"); } } } // 使用反射机制获取该包下所有的类已经存在bean的注解类 public List<Class> findClassExisService() throws Exception { // 1.使用反射机制获取该包下所有的类 if (StringUtils.isEmpty(packageName)) { throw new Exception("扫包地址不能为空!"); } // 2.使用反射技术获取当前包下所有的类 List<Class<?>> classesByPackageName = ClassUtil.getClasses(packageName); // 3.存放类上有bean注入注解 List<Class> exisClassesAnnotation = new ArrayList<Class>(); // 4.判断该类上属否存在注解 for (Class classInfo : classesByPackageName) { // 确定就是这个注解 ExtService extService = (ExtService) classInfo.getAnnotation(ExtService.class); if (extService != null) { exisClassesAnnotation.add(classInfo); continue; } } return exisClassesAnnotation; } // 初始化bean对象 public ConcurrentHashMap<String, Object> initBean(List<Class> listClassesAnnotation) throws InstantiationException, IllegalAccessException { ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap<String, Object>(); for (Class classInfo : listClassesAnnotation) { // 初始化对象 Object newInstance = classInfo.newInstance(); // 转成小写 String beanId = toLowerCaseFirstOne(classInfo.getSimpleName()); concurrentHashMap.put(beanId, newInstance); } return concurrentHashMap; } // 首字母转小写 public static String toLowerCaseFirstOne(String s) { if (Character.isLowerCase(s.charAt(0))) return s; else return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString(); } }
测试(里面有思路)
package com.qingruihappy3; import com.qingruihappy3.service.UserService; import com.qingruihappy3.spring.ClassPathXmlApplicationContext; import java.util.concurrent.ConcurrentHashMap; import com.qingruihappy3.service.OrderService; public class Test001 { public static void main(String[] args) throws Exception { //1,扫包 ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("com.qingruihappy3"); //2,把有service注解的对象放到map容器中来,(其实这一步可以一并放在步骤3中实现的,但是为了好理解一下,单独拆出来了) ConcurrentHashMap<String, Object> map = app.setMap(); //3,从容器中取出值来(注意这个时候不仅要取userServiceImpl对象,还要取userdao对象的),并且给它的带有resource注解的属性值(userdao)赋值 UserService userService = (UserService) app.getBean(map,"userServiceImpl"); userService.add(); OrderService orderService = (OrderService) app.getBean(map,"orderServiceImpl"); orderService.addOrder(); } }