目录
概述
1.Component注解定义
2.Reject注解定义
3.User对象定义
4.UserService实现
5.UserController实现
6.IocContext ioc bean容器
7.IocUtils ioc的依赖注入
8.模拟调用UserController
结果
概述
IOC (Inversion of Control) 控制反转。熟悉Spring的应该都知道。那么具体是怎么实现的呢?下面我们通过一个例子说明。
1.Component注解定义
/**
* 类上的注解:用来告诉ioc容器哪些类需要托管
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
}
先定义一个Component注解,主要被Component注解修饰的类都是需要被ioc容器管理的类。
2.Reject注解定义
/**
* 属性上的注解:初始化一个类的时候,如果类中有注解需要注入其他类
* 去ioc中找,找不到需要再初始化
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Inject {
}
定义一个@Inject注解,只要是被@Inject注解注释的属性都会自动注入,实现IOC功能。
3.User对象定义
@Data
public class User {
private String userName;
private int userAge;
public User(String userName,int userAge){
this.userAge = userAge;
this.userName = userName;
}
@Override
public String toString() {
return "User [userName=" + userName + ",userAge=" + userAge + "]";
}
}
就是一个普通的模型bean
4.UserService实现
@Component
public class UserService {
public User getUser(){
return new User("xl",30);
}
}
使用@Component注解标注该类是受容器管理的类。
5.UserController实现
@Component
public class UserController {
@Inject
private UserService userService;
public void getUser(){
User user = userService.getUser();
System.out.println(user.toString());
}
}
使用@Component注解标注该类是受容器管理的类。
userService使用了@Inject自定义注解,表示该属性是容器自动注入该实例,实现IOC功能。
6.IocContext ioc bean容器
public class IocContext {
/**ioc容器 */
public static final Map<Class<?>,Object> applicationContext =
new ConcurrentHashMap<>(64);
static {
String packName = "com.damai.ioc";
// 遍历包下面全部的类,看是否有@Component注解,决定是否需要ioc容器托管
try{
initBean(packName);
}catch (Exception e){
e.printStackTrace();
}
}
private static void initBean(String packName){
try {
// 加载到ioc 容器
Enumeration<URL> urls = Thread.currentThread().
getContextClassLoader().getResources(packName.replace(".","/"));
while (urls.hasMoreElements()){
addClassByAnnotation(urls.nextElement().getPath(),packName);
}
// 实现注入功能
IocUtils.inject();
}catch (Exception e){
e.printStackTrace();
}
}
private static void addClassByAnnotation(String path,String packName) throws Exception{
System.out.println("path : "+path);
System.out.println("packName : "+packName);
File[] files = getClassFile(path);
if(files!=null){
for(File file : files){
String fileName = file.getName();
System.out.println(">>> fileName : "+fileName);
if(file.isFile()){
// 根据类的全名进行加载
Class<?> clazz = Class.forName(packName+"."+
fileName.substring(0,fileName.lastIndexOf(".")));
if(clazz.isAnnotationPresent(Component.class)){
// 将类和类的实例加载到容器中
applicationContext.put(clazz,clazz.newInstance());
}
}else{
addClassByAnnotation(file.getPath(),packName+"."+fileName);
}
}
}
}
private static File[] getClassFile(String filePath) {
return new File(filePath).listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return file.isFile() && file.getName().endsWith(".class") || file.isDirectory();
}
});
}
}
a.扫描加载指定包路径下的所有Class,并判断该Class 是否是@Component注解的类,如果是,则创建实例,并保存到applicationContext缓存中
b.调用IocUtils.inject(),进行依赖注入
7.IocUtils ioc的依赖注入
public class IocUtils {
public static void inject() {
System.out.println("IocUtils inject method");
// 获取ioc 容器中的map
Map<Class<?>,Object> map = IocContext.applicationContext;
try {
// map 的key 主要是已经加载到容器中的class
for(Map.Entry<Class<?>,Object> entry : map.entrySet()){
Class<?> clazz = entry.getKey();
// map 的value 主要是key 对应的实例
Object obj = entry.getValue();
Field[] fields = clazz.getDeclaredFields();
for(Field field :fields){
if(field.isAnnotationPresent(Inject.class)){
System.out.println(">>> field : "+field.getName()+field.getType());
Class<?> fieldClazz = field.getType();
field.setAccessible(true);
Object fieldObj = map.get(fieldClazz);
// 设置后,属性的实例就会注入,而不是null
// 将B 对象的实例fieldObj 注入到 A对象的的实例obj 中
field.set(obj,fieldObj);
}
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
8.模拟调用UserController
public class Main {
public static void main(String[] args) {
UserController userController =
(UserController) IocContext.applicationContext.get(UserController.class);
userController.getUser();
}
}
循环遍历 applicationContext中所有的Bean,判断每个Bean中是否有被@Inject注解修饰的属性,如果有则从applicationContext中获取要注入的实例,并使用反射实现自动注入功能。
结果
path : /D:/ideaStudy/springioc/target/classes/com/damai/ioc
packName : com.damai.ioc
>>> fileName : Component.class
>>> fileName : Inject.class
>>> fileName : IocContext$1.class
>>> fileName : IocContext.class
>>> fileName : IocUtils.class
>>> fileName : Main.class
>>> fileName : User.class
>>> fileName : UserController.class
>>> fileName : UserService.class
IocUtils inject method
>>> field : userServiceclass com.damai.ioc.UserService
User [userName=xl,userAge=30]
? (编辑:北几岛)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|