简单实现spring的IOC
当我们熟练使用Spring框架后 发现在项目中最常见的就是注解,那么注解到底是如何在后台运转的?
实际上在框架中我们使用的所有的注解本身都没有任何用处,在框架里边,注解本身只有一个表示的作用(类似于注解),在框架中的注解之所以能实现很多功能,原因是因为每一个注解下面都有大量的反射代码对其进行支持。
IOC 常用的注解如下:
@Component
@Repository
@Service
@Controller
DI 注解:
@Autowried
创建一个maven项目 导入依赖
后续会用到dom解析 导入dom4j依赖
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
创建Spring对应的自定义注解
@Component
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface Component {
String value() default "";
}
IOC的其他三个注解创建方式同上
@Autowrited
/**
* @Target({ElementType.FIELD}) 标识此注解只能用于属性上
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowrited {
String value() default "";
}
创建BeanFactory接口
/**
* IOC容器的顶层接口 里面定义从容器获取bean对象的基本方法
*/
public interface BeanFactory {
/**
* 根据ID获取bean对象
* @param name
* @return
*/
Object getBean(String name);
/**
* 根据类型获取bean
* @param classType
* @param <T>
*/
<T> T getBean(Class<T> classType);
}
创建ApplicationContext接口继承BeanFactory
public interface ApplicationContext extends BeanFactory{
}
创建ClassPathXmlApplicationCintext实现ApplicationContext接口
public class ClassPathXmlApplicationCintext implements ApplicationContext{
/**
* 存储对象的容器
*/
private static Map<String,Object> map = new HashMap<String, Object>();
/**
* 用来存储文件路径的
*/
private List<String> path = new ArrayList<String>();
/**
* 通过构造方法传递过来配置文件名称
* @param config
*/
public ClassPathXmlApplicationCintext(String config) {
readConfig(config);
}
private void readConfig(String config){
SAXReader readeer = new SAXReader();
try {
String path2 = ClassPathXmlApplicationCintext.class.getResource("/").getPath();
Document read =readeer.read(path2+config);
getPath(read);
}catch (DocumentException e){
e.printStackTrace();
}
}
private void getPath(Document read){
/**
* 先获得配置文件最外层标签
*/
Element element = read.getRootElement();
/**
* 获得context-scan 标签
*/
Element el = element.element("context-scan");
/**
* 获得context-sccan标签中base-package属性的值
*/
String base = el.attributeValue("base-package");
String path2 = ClassPathXmlApplicationCintext.class.getResource("/").getPath();
base = base.replace(".","/");
String path = path2 + base;
doFile(new File(path));
//将上边的路径换成 包名+类名
for (int i = 0; i < this.path.size(); i++) {
String s = this.path.get(i).replace(path2.replace("/","\\").replaceFirst("\\\\",""),"").replace("\\",".").replace(".class","");
this.path.set(i,s);
}
//迭代 .xml 文件中的 bean 标签
Iterator<Element> ite = element.elementIterator("bean");
while (ite.hasNext()){
Element next = ite.next(); //获得bean标签对象
String cValue = next.attributeValue("class");
try {
map.put(next.attributeValue("id"),Class.forName(cValue).newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
//初始化工厂
initFactory();
xmlDi(element.elementIterator("bean"));
annDi();
}
/**
* xml手动装配
*/
public void xmlDi(Iterator<Element> ite){
while (ite.hasNext()){
Element next = ite.next();
Iterator<Element> iterator = next.elementIterator();
String id = next.attributeValue("id");
while (iterator.hasNext()){
Element next2 = iterator.next();//获得bean标签里的property标签
String name = next2.attributeValue("name");//获得name属性的值
String value = next2.attributeValue("value");//获得value属性的值
Object obj = map.get(id);//获得IOC容器中的对象
Class class1 = obj.getClass(); //获得了对象的反射对象
Field[] fields = class1.getDeclaredFields();
for (Field field : fields) {
if (field.getName().equals(name)) {
field.setAccessible(true);
try {
if (value == null || value.equals("")) {
Object object = map.get(next2.attributeValue("ref"));
if (object==null){
throw new RuntimeException("没有ID是"+next2.attributeValue("ref")+"的bean对象,请检查配置文件");
}else {
field.set(obj,object);
}
} else {
if (field.getType().getName().equals("java.lang.Integer")||field.getType().getName().equals("int")){
field.set(obj,Integer.valueOf(value));
}
if (field.getType().getName().equals("java.lang.String")){
field.set(obj, value);
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
}
/**
* 注解自动装配
*/
public void annDi(){
Collection<Object> values = map.values();//获得IOC容器中的所有对象
Iterator<Object> iterator = values.iterator();
while (iterator.hasNext()){
Object next = iterator.next(); //取出IOC容器中的对象
Class class1 = next.getClass(); //获得对象的反射
Field[] fields = class1.getDeclaredFields(); //获得对象的所有属性
for (Field field : fields) {
Autowrited annotation = field.getAnnotation(Autowrited.class);
if (annotation!=null){
field.setAccessible(true);
String value = annotation.value();
try {
if (value.equals("")){
field.set(next,getBean(field.getType()));
}else {
field.set(next,map.get(value));
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
/**
* 递归
* @param file
*/
private void doFile(File file){
if (file.isDirectory()){ //判断是否是文件夹
File[] files = file.listFiles(); //取出文件夹中所有的文件📂
for (File file2 : files) {
doFile(file2);
}
}else { //递归出口
if (file.getName().endsWith(".class")){
path.add(file.getPath()); //将文件添加到集合中
}
}
}
public void initFactory(){
for (String string : path) {
try {
//首先判断我们的类是否使用了IOC注解
boolean b = Class.forName(string).isAnnotationPresent(Component.class);
boolean c = Class.forName(string).isAnnotationPresent(Repository.class);
boolean d = Class.forName(string).isAnnotationPresent(Service.class);
boolean e = Class.forName(string).isAnnotationPresent(Controller.class);
String value = "abc";
if (b){
//获得到注解对象
Component an = Class.forName(string).getAnnotation(Component.class);
value = an.value();
}
if (c){
//获得到注解对象
Repository an = Class.forName(string).getAnnotation(Repository.class);
value = an.value();
}
if (d){
//获得到注解对象
Service an = Class.forName(string).getAnnotation(Service.class);
value = an.value();
}
if (e){
//获得到注解对象
Controller an = Class.forName(string).getAnnotation(Controller.class);
value = an.value();
}
if (value.equals("")){
map.put(string,Class.forName(string).newInstance());
}else if (value.equals("abc")){
//fsajkfhjkdsahfjj
} else {
map.put(value,Class.forName(string).newInstance());
}
}catch (Exception e){
e.printStackTrace();
}
}
}
public Object getBean(String name) {
return map.get(name);
}
public <T> T getBean(Class<T> classType) {
Iterator<Object> iterator = map.values().iterator();
while (iterator.hasNext()){
Object next = iterator.next();
if (next.getClass().getName().equals(classType.getName())||classType.isAssignableFrom(next.getClass())){
return (T)next;
}
}
return null;
}
}
写一个XML文件进行测试
<?xml version="1.0" encoding="UTF-8" ?>
<bases>
<!--定义一个扫描路径 哪些包下的类可以被IOC容器管理-->
<context-scan base-package="com.zhiyou">
</context-scan>
<bean id="aa" class="com.zhiyou.APP">
<property name="name" value="憨憨"/>
<property name="in" value="123"/>
<property name="a" ref="hanhan"/>
</bean>
</bases>
public static void main(String[] args) {
ClassPathXmlApplicationCintext app =
new ClassPathXmlApplicationCintext("application.xml");
System.out.println(app.getBean("hanhan"));
}
测试没问题的话 可以通过maven命令对项目内进行打包
在别的项目进行导入使用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k5csJIxz-1623854078596)(E:\文件\SQLimg\image-20210616223001930.png)]
主要目的
1: 提高思维能力,扩展能力
2: 知道框架(注解)为什么能实现这些功能
``
public static void main(String[] args) {
ClassPathXmlApplicationCintext app =
new ClassPathXmlApplicationCintext("application.xml");
System.out.println(app.getBean("hanhan"));
}
测试没问题的话 可以通过maven命令对项目内进行打包
在别的项目进行导入使用
主要目的
1: 提高思维能力,扩展能力
2: 知道框架(注解)为什么能实现这些功能
3: 综合技术练习,反射使用场景练习,还是提升思维能力