注解就是给程序看的注释。之所以这样说,是因为我想用一句话讲清楚注解和注释的区别。
注释是给人看的解释,提示一下程序员这个类,这个方法的作用是什么,怎么用。比如我要写一个方法打印当前时间,那我会在方法上面加一段注释,这样的话别人在看到我的代码的时候可以快速判断是不是他需要的东西。
/**
* 打印当前时间
*
**/
public void printTime() {
System.out.println(new Date());
}
注解是给程序看的注释。意思是说注解也是对类、方法、属性的一种解释,但是这个解释不仅仅程序员能看懂,程序也能看懂,程序是怎么看懂注解的???举个例子:
Spring里面有大量注解,我这里以@Autowired举例说明。这个注解可以放在构造器、方法和属性上面,我这里以加在属性上进行说明。
@Controller
public class UserController {
@Autowired
private ISysUserService userService;
}
@Autowire的作用是为成员变量注入一个对象,这我们在学习Spring的时候老师就讲过了,那注解就已经发挥了他的第一个作用----让程序员看懂。那程序(Spring)是怎么通过@Autowired知道要给userService注入一个对象的呢?往下看:
我们先不管Spring是怎么实现的,先思考一个问题,如果我要实现这一点,我要做哪些事情?
我要通过注解,在userController对象被创建的时候或者被创建之后拿到变量,拿到变量之后new一个SysUserServiceImpl,赋值给userService。目标已经清晰,逐个击破!
怎么判断userService是否被@Autowired标记?反射机制,通过反射拿到UserController的Class对象,拿到类的属性,调用isAnnotationPresent()方法判断是否被Autowired标记,看代码:
/**
* 判断UserController.userService 是否被@Autowire标记
*
* @return boolean
**/
public boolean checkAutowire() throws ClassNotFoundException, NoSuchFieldException {
// 1. 获取SysUserController类信息 userClass
Class<?> userClass = Class.forName(String.valueOf(UserController.class));
// 2. 拿到属性 userService
Field userService = userClass.getField("userService");
// 3. 判断userService是否被@Autowired标记
return userService.isAnnotationPresent(Autowired.class);
}
下一个要解决的问题是:什么时候怎么注入对象?
我们有两种选择:①用构造函数访问变量、②用setter()方法访问变量。两种都可以,这里我选择第二种:我要在userController对象创建完成之后,调用setter方法给userService变量注入一个对象,看代码:
public UserController getSysUserController() throws NoSuchFieldException, ClassNotFoundException {
UserController sysUserController = new UserController();
if (checkAutowire()) {
sysUserController.setUserService(new SysUserServiceImpl());
}
return sysUserController;
}
OK,到这里我们的目的就已经达到了。我们成功利用@Autowired注解给Controller注入了Service对象,程序看懂了注解,它发现checkAutowire()返回true后就调用 setter()方法注入了一个对象。
恭喜你,你手写了@Autowired的实现。有人可能会说,放屁。我用Spring的时候直接加注解就可以了,你这一顿操作下来userController这个对象要自己创建,那我要Spring干嘛? 如果你也有这个疑问,那你不妨带着今天对注解的理解思考一下如果要你来实现@Controller,你会怎么做?
嘿嘿嘿,挖个坑,欢迎进入源码的世界!如有高见欢迎评论区留言呢!