本例在 springmvc 中实现,围绕三步进行:
(1):定位:配置文件,读取扫描路径,保存扫描到的类
(2):加载:读取扫描路径,保存扫描到的类
(3):注册:注册扫描到的类
环境说明:
webapp----》WEB-INF:
<servlet>
<servlet-name>qingnianmvc</servlet-name>
<servlet-class>com.qingnian.spring.controller.DispatchServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>qingnianmvc</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
classpath: 下生成对应的配置文件applicationContext.properties
#所要扫描的包路径
spring.scan=com.qingnian.demo
仿造 spring 生成自定义注解
import java.lang.annotation.*;
/*
任涛 -----专用
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyService {
String value() default "";
}
import java.lang.annotation.*;
/*
任涛 -----专用
*/
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestParam {
String value() default "";
}
import java.lang.annotation.*;
/*
任涛 -----专用
*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestMapping {
String value() default "";
}
import java.lang.annotation.*;
/*
任涛 -----专用
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyController {
String value() default "";
}
import java.lang.annotation.*;
/*
任涛 -----专用
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAutowried {
String value() default "";
}
核心类:DispatchServlet
import com.qingnian.demo.controller.StudentController;
import com.qingnian.spring.annotaion.MyAutowried;
import com.qingnian.spring.annotaion.MyController;
import com.qingnian.spring.annotaion.MyService;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.*;
/*
任涛 -----专用
*/
public class DispatchServlet extends HttpServlet {
//配置文件
private Properties contextConfig=new Properties();
//存放包扫描扫描到的class全路径名称
private List<String> classNames=new ArrayList<>();
//存放<对象名称,对象本身>map (可理解为一个容器)
//spring 中存放的是对象的定义,而不是对象
private Map<String,Object> beanMap=new HashMap<>();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//super.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("执行了doPost方法");
}
@Override
public void init(ServletConfig config) throws ServletException {
//初始化开始
//定位配置文件
doLoadCongig(config.getInitParameter("contextConfigLocation"));
//加载配置文件中的内容
doScanner(contextConfig.getProperty("spring.scan"));
//注册对象
doInstance();
//自动注入
doAutowired();
//测试
StudentController studentController = (StudentController) beanMap.get("studentController");
String student = studentController.getOne("ceshi:1");
System.out.println(student);
//如果为springmvc ,会多一个 HandlerMapping 组件,用于存放<url,controller>
//将对应的mapping路径,对应方法保存在map中,前端发送请求过来时,快速定位执行
initHandlerMapping();
}
private void initHandlerMapping() {
}
private void doAutowired() {
if(null==beanMap){
return;
}
//遍历beanMap :判断对象的属性是否需要注入对应对象
beanMap.forEach((k,entity)->{
Field[] fields = entity.getClass().getDeclaredFields();
for (Field field : fields) {
if(field.isAnnotationPresent(MyAutowried.class)){
//需要自动注入
MyAutowried autowried = field.getAnnotation(MyAutowried.class);
String autoBeanname= autowried.value().trim();
if("".equals(autoBeanname)){
//默认填充的对象名称:首字母小写
autoBeanname=lowercase(field.getType().getSimpleName());
}
//为字段注入内容
field.setAccessible(true);
try {
field.set(entity, beanMap.get(autoBeanname));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
});
}
private void doInstance() {
if(null==classNames){
return;
}
for (String className : classNames) {
//通过反射构建对象
try {
Class<?> aClass = Class.forName(className);
if (aClass.isAnnotationPresent(MyController.class)){
//为有 @MyController 注解修饰的Java类生成对应的对象
//首字母小写
String beanName=lowercase(aClass.getSimpleName());
beanMap.put(beanName,aClass.newInstance());
}else if(aClass.isAnnotationPresent(MyService.class)){
MyService myService = aClass.getAnnotation(MyService.class);
//获取注解中的value值:如果有指定值。则不用默认首字母小写策略
String beanName = myService.value();
if ("".equals(beanName.trim())){
beanName=lowercase(aClass.getSimpleName());
}
beanMap.put(beanName,aClass.newInstance());
//判断该类是否为有实现接口
Class<?>[] interfaces = aClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
//遍历所实现的接口,生成对应<接口名称,实现类对象>
beanMap.put(lowercase(anInterface.getSimpleName()),aClass.newInstance());
}
}else{
continue;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
//首字母小写的方法
private String lowercase(String beanName) {
char[] chars = beanName.toCharArray();
chars[0]+=32;
return String.valueOf(chars);
}
//扫描指定包路径,将对应的完整类名放入list
private void doScanner(String packageName) {
URL url = this.getClass().getClassLoader().getResource("/" + packageName.replaceAll("\\.", "/"));
File filedir=new File(url.getFile());
for (File file : filedir.listFiles()) {
if(file.isDirectory()){
doScanner(packageName+"."+file.getName());
}else {
classNames.add(packageName+"."+file.getName().replaceAll(".class",""));
}
}
}
private void doLoadCongig(String location) {
//spring -> reader 解析器读取配置文件的内容
InputStream stream = this.getClass().getClassLoader().getResourceAsStream(location.replace("classpath:", ""));
try {
contextConfig.load(stream);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != stream) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
下面是测试代码:
package com.qingnian.demo.service;
/*
任涛 -----专用
*/
public interface StudentService {
String selectOne(String id);
}
package com.qingnian.demo.service.impl;
import com.qingnian.demo.service.StudentService;
import com.qingnian.spring.annotaion.MyService;
/*
任涛 -----专用
*/
@MyService
public class StudentServiceImpl implements StudentService {
@Override
public String selectOne(String id) {
return "StudentServiceImpl返回学生1:"+id;
}
}
package com.qingnian.demo.controller;
import com.qingnian.demo.service.StudentService;
import com.qingnian.spring.annotaion.MyAutowried;
import com.qingnian.spring.annotaion.MyController;
import com.qingnian.spring.annotaion.MyRequestMapping;
import com.qingnian.spring.annotaion.MyRequestParam;
/*
任涛 -----专用
*/
@MyController
@MyRequestMapping("Student")
public class StudentController {
@MyAutowried
private StudentService studentService;
@MyRequestMapping("/get/id")
public String getOne(@MyRequestParam("id")String id){
return studentService.selectOne(id);
}
}