接上回书:https://blog.youkuaiyun.com/qq_34785454/article/details/84728533
上一篇里我自己碎碎念了一下,要是能有手写的autowired就好了,今天决定自己动手写了。
直接上代码:
自定义的两个注解:
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAutowired {
String value() default "";
}
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyService {
String value() default "";
}
在servlet初始化时,带@MyService注解的类也应该实例化为bean存入map当中,这里就不贴代码了,原代码加一个判断条件的事儿。
在servlet的init方法的最后调用自动注入方法:
/**
* 实现自动注入
*/
private void doAutowired() {
if(ioc.isEmpty()) {
return;
}
for(Entry<String, Object> e : ioc.entrySet()) {
Class<? extends Object> clazz = e.getValue().getClass();
if((!clazz.isAnnotationPresent(MyController.class))&&(!clazz.isAnnotationPresent(MyService.class)))
continue;
//遍历每个类中的域
Field[] fields = clazz.getDeclaredFields();
for(Field f:fields) {
Annotation[] annotations = f.getAnnotations();
for(Annotation a : annotations) {
if(a instanceof MyAutowired){
String fieldName = f.getName() + "Impl";
//搜索实例化bean进行注入
Object o = ioc.get(fieldName);
if(o != null) {
try {
//这句代码一定要加!一定要加!一定要加!不然的话controller里的成员变量如果不是public,会因为没有访问权限而无法实例化赋值,就报异常了
f.setAccessible(true);
f.set(e.getValue(), o);
} catch (IllegalArgumentException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IllegalAccessException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
}
}
}
差不多就大功告成了。
新建service接口和实现类:
public interface TestService {
String helloWorld();
}
import com.wmx.annotation.MyService;
import com.wmx.core.service.TestService;
@MyService
public class TestServiceImpl implements TestService{
@Override
public String helloWorld() {
return "33333aaaaa";
}
}
controller里实现注入:
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.wmx.annotation.MyAutowired;
import com.wmx.annotation.MyController;
import com.wmx.annotation.MyRequestMapping;
import com.wmx.annotation.MyRequestParam;
import com.wmx.core.service.TestService;
@MyController
@MyRequestMapping("/test")
public class TestController {
@MyAutowired
TestService testService;
@MyRequestMapping("/doTest")
public void test1(HttpServletRequest request, HttpServletResponse response,
@MyRequestParam("param") String param){
System.out.println(param);
try {
response.getWriter().write( "doTest method success! param:"+param);
} catch (IOException e) {
e.printStackTrace();
}
}
@MyRequestMapping("/doTest2")
public void test2(HttpServletRequest request, HttpServletResponse response){
try {
response.getWriter().println("doTest2 method success!"+testService.helloWorld());
} catch (IOException e) {
e.printStackTrace();
}
}
}
将项目部署到tomcat上,启动服务,访问
得到结果:
这里看出是返回了testservice接口的helloworld方法的值,说明自动注入调用成功。
整个过程里踩的最大的坑就是注入的时候关于成员变量的访问权限的部分,具体可以参考代码里的注释,就是那句代码一定要加,不然注入会失败,报异常。
参考:
https://blog.youkuaiyun.com/weixin_36184484/article/details/62885811
https://bbs.youkuaiyun.com/topics/340030757
感谢大佬们