🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
下面来模拟一下Spring的注解开发,关注点就是你<mark>不需要`new`一个对象,依然可以访问该对象的方法和属性,那是因为该类已经被反射并`new`好了</mark>。 <br/> 本节示例代码下载地址:https://gitee.com/flymini/spring/tree/master/mnzj <br/> 步骤如下: [TOC] # 1. 创建一个Web项目 # 2. 代码封装过程 **1. 封装注解** (1)*`org.example.mnzj.anno.Bean`* ```java package org.example.mnzj.anno; import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Bean { String value(); } ``` (2)*`org.example.mnzj.anno.Property`* ```java package org.example.mnzj.anno; import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Property { String value(); } ``` **2. 将上面定义的两个注解应用到Java类中** (1)dao层 *`org.example.mnzj.dao.StudentDao`* ```java package org.example.mnzj.dao; public interface StudentDao { Integer queryStudentCounts(); } ``` *`org.example.mnzj.dao.impl.StudentDaoImpl`* ```java package org.example.mnzj.dao.impl; import org.example.mnzj.anno.Bean; import org.example.mnzj.dao.StudentDao; @Bean("studentDao") public class StudentDaoImpl implements StudentDao { public Integer queryStudentCounts() { System.out.println("StudentDaoImpl.queryStudentCounts"); return null; } } ``` (2)service层 *`org.example.mnzj.service.StudentService`* ```java package org.example.mnzj.service; public interface StudentService { Integer queryStudentCounts(); } ``` *`org.example.mnzj.service.impl.StudentServiceImpl`* ```java package org.example.mnzj.service.impl; import org.example.mnzj.anno.Bean; import org.example.mnzj.anno.Property; import org.example.mnzj.dao.StudentDao; import org.example.mnzj.service.StudentService; @Bean("studentService") public class StudentServiceImpl implements StudentService { @Property("studentDao") private StudentDao studentDao; public Integer queryStudentCounts() { System.out.println("StudentServiceImpl.queryStudentCounts"); return studentDao.queryStudentCounts(); } } ``` **3. 对被`@Bean`和`@Property`注解标记的类进行反射** *`org.example.mnzj.common.AnnotationFactory`* ```java package org.example.mnzj.common; import org.example.mnzj.anno.Bean; import org.example.mnzj.anno.Property; import java.io.File; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; public class AnnotationFactory { private static Map<String, Object> map = new HashMap<String, Object>(); public static Object getInstance(String key) { return map.get(key); } static { // 获取.java文件编译后的.class文件所在的目录 String path = AnnotationFactory.class.getClassLoader().getResource("").getPath(); File file = new File(path); initBeans(path); // 初始化被@Bean注解标记的类 initProperties(); // 初始化被@Property注解标记的类 } /** * 找到并初始化被@Bean注解标记的类 * * @param path String, .class文件所在的目录 */ private static void initBeans(String path) { File file = new File(path); File[] subFiles = file.listFiles(); for (File subFile : subFiles) { if (subFile.isDirectory()) { initBeans(subFile.getPath()); } else { // 实例化被@Bean注解的类 initBean(subFile.getPath()); } } } /** * 实例化被@Bean注解标记的类 * * @param path String, .class文件所在的目录 */ private static void initBean(String path) { if (!path.endsWith(".class")) { return; } // 获取被@Bean注解标记的类的完全限定名 int begin = AnnotationFactory.class.getClassLoader().getResource("").getPath().length(); int end = path.lastIndexOf("."); String className = path.substring(begin - 1, end); className = className.replace("\\", "."); try { Class cls = Class.forName(className); // 加载类 // 判断该类是否被@Bean注解标记 if (cls.isAnnotationPresent(Bean.class)) { Object instance = cls.newInstance(); // 实例化该类 Bean annotation = (Bean) cls.getDeclaredAnnotation(Bean.class); map.put(annotation.value(), instance); } } catch (Exception e) { e.printStackTrace(); } } /** * 实例化被@Property注解标记的属性 */ private static void initProperties() { for (Object instance : map.values()) { Field[] fields = instance.getClass().getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Property.class)) { Property annotation = field.getAnnotation(Property.class); String key = annotation.value(); Object obj = map.get(key); field.setAccessible(true); try { field.set(instance, obj); } catch (Exception e) { e.printStackTrace(); } } } } } } ``` **4. 封装controller层** (1)*`org.example.mnzj.common.BaseServlet`* ```java package org.example.mnzj.common; import org.example.mnzj.anno.Property; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.lang.reflect.Field; import java.lang.reflect.Method; public class BaseServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) { String methodName = request.getParameter("method"); try { Method method = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); method.setAccessible(true); String url = (String) method.invoke(this, request, response); if (url == null) { return; } if (url.startsWith("redirect:")) { int index = url.indexOf(":"); url = url.substring(index + 1); response.sendRedirect(url + ".jsp"); } else { request.getRequestDispatcher(url + ".jsp").forward(request, response); } } catch (Exception e) { e.printStackTrace(); } } /** * 对继承该类的子类的成员属性进行赋值 * * @throws ServletException */ @Override public void init() throws ServletException { Field[] fields = this.getClass().getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Property.class)) { Property annotation = field.getAnnotation(Property.class); String key = annotation.value(); Object obj = AnnotationFactory.getInstance(key); try { field.setAccessible(true); field.set(this, obj); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } } ``` (2)*`org.example.mnzj.controller.StudentController`* ```java package org.example.mnzj.controller; import org.example.mnzj.anno.Property; import org.example.mnzj.common.BaseServlet; import org.example.mnzj.service.StudentService; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/student") public class StudentController extends BaseServlet { @Property("studentService") private StudentService studentService; private String welcome(HttpServletRequest request, HttpServletResponse response) { System.out.println("IndexController.doGet方法执行-----start"); studentService.queryStudentCounts(); System.out.println("IndexController.doGet方法执行-----end"); return null; } } ``` **5. 测试** 启动项目后访问 http://localhost:8080/mnzj_war_exploded/student?method=welcome ,控制台打印的结果如下: ``` IndexController.doGet方法执行-----start StudentServiceImpl.queryStudentCounts StudentDaoImpl.queryStudentCounts IndexController.doGet方法执行-----end ``` 上面写了那么多,其目的就想实现一个功能:我不`new`一个对象,但是我依然能够访问它的方法。 <br/> 在上面的代码中,`StudentServiceImpl ` 中调用了`StudentDao.queryStudentCounts`方法;在 `StudentController` 中调用了`StudentService.queryStudentCounts`方法。但是请注意我并没有实例化`StudentDaoImpl`和`StudentServiceImpl`类,因为这两个类被`@Bean`注解标记,作为属性时被`@Property`注解标记,然后在 `AnnotationFactory` 反射了被这两个注解标记的类并实例化了这个两个类,并在 `BaseServlet` 的`init`方法中对继承`BaseServlet`的子类的属性进行赋值,所以当我们调用方法时,对象已在`AnnotationFactory`帮我们自动实例化了。