版权声明:转载请注明原创 https://blog.csdn.net/qq_42151769/article/details/89151548
介绍: 最近看了一些别人的关于spring ioc/aop的博客,在别人基础上,实现以下spring ioc/aop简易的原理,在此感谢别人的分享.
使用java注解,反射机制,完成spring IOC容器和依赖注入的功能,模仿注解 Controller/Service/Component/Repository/Autowired的使用以及原理实现
项目的结构截图如下,后续完善AOP等功能
自定义的注解有:
@MyAutowired
package com.hf.aopdemo.ioc.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Description: 自定义依赖注入注解
* @Date: 2019/4/8
* @Auther:
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyAutowired {
String value() default "";
}
@MyService
package com.hf.aopdemo.ioc.annotation;
import java.lang.annotation.*;
/**
* @Description: 自定义service注解
* @Date: 2019/4/8
* @Auther:
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyService {
String value() default "";
}
@MyController
package com.hf.aopdemo.ioc.annotation;
import java.lang.annotation.*;
/**
* @Description: 自定义controller注解
* @Date: 2019/4/8
* @Auther:
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyController {
String value() default "";
}
@MyComponent
package com.hf.aopdemo.ioc.annotation;
import java.lang.annotation.*;
/**
* @Description: 自定义component
* @Date: 2019/4/8
* @Auther:
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyComponent {
String value() default "";
}
@MyRepository
package com.hf.aopdemo.ioc.annotation;
import java.lang.annotation.*;
/**
* @Description: 自定义MyRepository注解
* @Date: 2019/4/9
* @Auther:
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface MyRepository {
String value() default "";
}
自定义加载ioc容器初始化过程中的业务异常类:
package com.hf.aopdemo.ioc.exception;
/**
* @Description: 自定义加载ioc bean异常
* @Date: 2019/4/8
* @Auther:
*/
public class InitBeanException extends RuntimeException {
public InitBeanException(String msg){
super(msg);
}
public InitBeanException(Throwable e){
super(e);
}
}
下面的就是核心代码了:
1.定义获取Bean对象的接口: MyBeanContext
package com.hf.aopdemo.ioc.context;
/**
* @Description:
* @Date: 2019/4/8
* @Auther:
*/
public interface MyBeanContext {
/**
* 从ioc容器中根据名称获取对应的bean对象
* @param beanName
* @return
*/
public Object getBean(String beanName);
}
2.具体加载初始化IOC/依赖注入的逻辑类: 这是一个抽象类
package com.hf.aopdemo.ioc.context;
import com.hf.aopdemo.ioc.annotation.*;
import com.hf.aopdemo.ioc.exception.InitBeanException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.*;
/**
* @Description: 加载bean的系列逻辑
* @Date: 2019/4/8
* @Auther:
*/
@Slf4j
public abstract class AbsBeanContext implements MyBeanContext{
/**
* 定义IOC容器 对应的是map: key:类名称简写(首字母小写) -- value:创建的对象
*/
private final Map<String,Object> IOCMap = new HashMap<>();
/**
* 包扫描路径集合
*/
private final List<String> scanPaths = new ArrayList<>();
/**
* 获取自定义IOC容器中的对象
* @param beanName
* @return
*/
@Override
public Object getBean(String beanName) {
return IOCMap.get(beanName);
}
/**
* 获取包的路径
* @param scanPackage
*/
public void scanPackage(String scanPackage){
if(StringUtils.isEmpty(scanPackage)){
throw new InitBeanException("包名称不能为空");
}
List<String> packageNames = new ArrayList<>();
//判断传入是否为多个包名
if(scanPackage.contains(",")){
packageNames = Arrays.asList(scanPackage.split(","));
}else{
packageNames.add(scanPackage);
}
packageNames.stream().forEach(packageName -> {
//获取包对应的统一资源路径
URL url = Thread.currentThread().getContextClassLoader().getResource(packageName.replaceAll("\\.", "/"));
//转换为file处理
File file = new File(url.getFile());
//遍历改目录下面的所有文件/文件夹
Arrays.stream(file.listFiles()).forEach(var -> {
if(var.isDirectory()){
scanPackage(packageName + "." + var.getName());
}else{
scanPaths.add(packageName + "." + var.getName().replaceAll(".class",""));
}
});
});
}
/**
* 初始化IOC容器
*/
public void initIOC(){
this.scanPaths.stream().forEach(var -> {
try {
Class<?> clzz = Class.forName(var);
//IOC容器的key值,对应的是类名的首字母小写,如果有接口,就获取接口的名称
String key = "";
//判断作用在controller上的注解,
//TODO 暂时先不考虑MyComponent作用在sevrice/mapper层
if(clzz.isAnnotationPresent(MyComponent.class) || clzz.isAnnotationPresent(MyController.class)){
//获取注解上面的值
MyController controller = clzz.getAnnotation(MyController.class);
MyComponent component = clzz.getAnnotation(MyComponent.class);
if(null != controller){
//类似spring 的存储到ioc,首字母是小写的
key = firstCharToLower(controller.value());
}else{
key = firstCharToLower(component.value());
}
if(StringUtils.isEmpty(key)){
//类似spring 给定默认值
key = firstCharToLower(clzz.getSimpleName());
}
//存储到ioc容器,key:类名称简写(首字母小写) -- value:创建的对象
IOCMap.put(key,clzz.newInstance());
}else if(clzz.isAnnotationPresent(MyService.class)){
//这个是打上了MyService注解的,需要获取到实现的接口
MyService service = clzz.getAnnotation(MyService.class);
key = service.value();
this.handlerAnnocation(key,clzz);
}else if(clzz.isAnnotationPresent(MyRepository.class)){
MyRepository repository = clzz.getAnnotation(MyRepository.class);
key = repository.value();
this.handlerAnnocation(key,clzz);
}else{
log.error(clzz.getSimpleName() + ":没有找到自定义的注解....." );
return;
}
} catch (Exception e) {
log.error("不能通过路径创建class字节码对象....");
throw new InitBeanException(e);
}
});
}
/**
* 针对MyRepository注解/MyService注解的IOC容器初始化处理
* @param key
* @param clzz
*/
private void handlerAnnocation(String key,Class<?> clzz){
if(StringUtils.isEmpty(key)){
//用户没有给注解打上指定值,那么久去指定默认值
//获取实现接口
Class<?>[] interfaces = clzz.getInterfaces();
/**
* 判断是否有上级接口,如果木有就直接存入改类的名称作为key; 如果有就获取到接口的名称作为key存入IOCMap
*/
if(!CollectionUtils.isEmpty(Arrays.asList(interfaces))){
Arrays.stream(interfaces).forEach(var1 -> {
try {
IOCMap.put(firstCharToLower(var1.getSimpleName()),clzz.newInstance());
} catch (Exception e) {
e.printStackTrace();
}
});
}else{
//没有实现接口或者没有给定注解值
//给定默认值
key = firstCharToLower(clzz.getSimpleName());
}
}
if(!StringUtils.isEmpty(key)){
//加入IOCMap
try {
IOCMap.put(key,clzz.newInstance());
} catch (InstantiationException | IllegalAccessException var2) {
log.error("<handlerAnnocation> can not newInstance.....:" + clzz.getSimpleName(),var2.getMessage(),var2);
}
}
}
/**
* @Autowired依赖注入,只做针对字段属性的注入
*/
public void autowiredInjection(){
this.IOCMap.entrySet().stream().forEach(map -> {
//取出对象的类型
Class<?> clzz = map.getValue().getClass();
//获取所有的字段
Field[] fields = clzz.getDeclaredFields();
//判断是否有MyAutowired注解
Arrays.stream(fields).filter((Field field) -> field.isAnnotationPresent(MyAutowired.class)).forEach(var -> {
//依赖注入
var.setAccessible(true);
//获取到注解值
String beanName = var.getAnnotation(MyAutowired.class).value();
if(StringUtils.isEmpty(beanName)){
//获取字段的类型,给定默认值
beanName = firstCharToLower(var.getType().getSimpleName());
}
try {
//给对象设置字段值,也就是给依赖注入设置对象
var.set(map.getValue(),IOCMap.get(beanName));
} catch (IllegalAccessException e) {
log.error("set field " + var.getName() + " error...",e.getMessage(),e);
}
});
});
}
/**
* 字符串首字母转换为小写
* @param source
* @return
*/
public String firstCharToLower(String source){
String result = "";
if(!StringUtils.isEmpty(source)){
StringBuilder builder = new StringBuilder();
result = builder.append(source.substring(0,1).toLowerCase()).append(source.substring(1)).toString();
}
return result;
}
}
3.真正的初始化IOC容器的类,该类用于完成IOC初始化和自动依赖注入
package com.hf.aopdemo.ioc.context;
import lombok.extern.slf4j.Slf4j;
/**
* @Description:
* @Date: 2019/4/9
* @Auther:
*/
@Slf4j
public class MyBaseContext extends AbsBeanContext{
/**
* 包扫描常量
*/
public String SCAN_PACKAGE = null;
/**
* 是否开启aop配置
*/
public boolean ENABLE_AOP = false;
/**
* 创建对象,默认加载bean系列初始化
*/
public MyBaseContext(String SCAN_PACKAGE,boolean ENABLE_AOP){
this.ENABLE_AOP = ENABLE_AOP;
this.SCAN_PACKAGE = SCAN_PACKAGE;
//扫包处理,获取到路径
this.scanPackage(this.SCAN_PACKAGE);
//初始化IOC容器
this.initIOC();
//MyAutowired依赖注入
this.autowiredInjection();
log.info("初始化IOCMap完成.......");
}
}
下面我们就做测试了:
新建controller,打上自定义注解
package com.hf.aopdemo.controller;
import com.hf.aopdemo.ioc.annotation.MyAutowired;
import com.hf.aopdemo.ioc.annotation.MyController;
import com.hf.aopdemo.service.UserService;
/**
* @Description:
* @Date: 2019/4/9
* @Auther:
*/
@MyController
public class UserController {
@MyAutowired
private UserService userService;
public String sayHello(){
String msg = userService.sayHello("world");
return msg;
}
}
新建service,打上自定义注解:
package com.hf.aopdemo.service;
/**
* @Description:
* @Date: 2019/4/9
* @Auther:
*/
public interface UserService {
String sayHello(String msg);
}
实现类如下:
package com.hf.aopdemo.service.impl;
import com.hf.aopdemo.ioc.annotation.MyService;
import com.hf.aopdemo.service.UserService;
/**
* @Description:
* @Date: 2019/4/9
* @Auther:
*/
@MyService
public class UserServiceImpl implements UserService {
@Override
public String sayHello(String msg) {
return new StringBuilder().append("hello,").append(msg).toString();
}
}
测试类:
package com.hf.aopdemo.ioc;
import com.hf.aopdemo.controller.UserController;
import com.hf.aopdemo.ioc.context.MyBaseContext;
import org.junit.Test;
/**
* @Description:
* @Date: 2019/4/9
* @Auther:
*/
public class IOCTest {
@Test
public void tt(){
//指定包名称
String scanPakage = "com.hf.aopdemo.service,com.hf.aopdemo.controller";
MyBaseContext context = new MyBaseContext(scanPakage, false);
UserController controller = (UserController) context.getBean("userController");
System.out.println(controller.sayHello());
}
}
运行可以看到测试结果: