原理:SpringIoC控制反转底层实现利用了java自身提供的反射技术来创建对象
Class.forName(classPath).newInstance();
通过这种方式,spring控制了对象的生命周期,可以随时自行增强对象,如DI依赖注入,如AOP,环绕通知在类创建前后增强功能,如Transaction事务加强等。
开发步骤
- 创建容器管理bean,并初始化容器-> [user,dept,hello]
- 创建spring容器,并初始化容器-> {hello=new Hello(),user=new Uer() }
- 提供getBean(),根据bean的名字,从spring容器中获取对应的对象
Bean.java
抽象Bean的定义,取代java中的Object,Spring框架中万物皆Bean。
package com;
/**
* Spring中万物皆是Bean,用于存放对象
* 管理Bean也是管理对象
* */
public class Bean {
//Bean的名字Id
private String name;
//Bean(java中的对象)对应的路径“包名.类名”
private String path;
/**
* 生成get,set方法给对象赋值
* */
public String getName() {
return name;
}
public String getPath() {
return path;
}
public void setName(String name) {
this.name = name;
}
public void setPath(String path) {
this.path = path;
}
}
SpringContext.java
逻辑复杂,IoC实现的核心,最关键点还是怎么创建对象实例:
package com;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 模拟spring框架
* 创建Bean
* 存放Bean
* 设置取出Bean的方法,有Bean就直接取出没有需要创建一个
* */
public class SpringContext {
//创建一个容器存放Bean
private List<Bean> beanFactory = new ArrayList<>();
//构造方法创建框架是自动执行
public SpringContext() throws Exception {
//创建一个Bean
Bean bean = new Bean();
bean.setName("Hello");
bean.setPath("com.Hello");
//将Bean加入容器
beanFactory.add(bean);
init();
}
/**
* 创建容器Key是类名Value是路径
* 通过Class.forName(path).newInstance()获取对象
* */
private final Map<String, Object> factoryBeanObject =
new ConcurrentHashMap<>();
public void init() throws Exception {
for(Bean b : beanFactory){
String key = b.getName();
//反射创建对象,作为value存入map
String path = b.getPath();
Object value = Class.forName(path).newInstance();
factoryBeanObject.put(key, value);
}
}
//3,getBean()有就直接取出来,没有就创建并放入容器
public Object getBean (String name){
return factoryBeanObject.get(name);
}
}
创建一个对象
package com;
/**
* 创建一个对象后面在交给Bean
* */
public class Hello {
public void hi(){
System.out.println("你好,springIOC");
}
}
测试类
package cn.tedu.spring;
import cn.tedu.design.SpringContext;
import cn.tedu.pojo.Hello;
public class TestMyIOC {
public static void main(String[] args) throws Exception {
SpringContext spring = new SpringContext();
Hello o = (Hello)spring.getBean("hello");
System.out.println(o);//cn.tedu.pojo.Hello@6d06d69c
o.hi();
}
}
模拟SpringDI的底层实现
package com.di;
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)
public @interface MyAutowired {
String value() default "";
}
创建一个Teacher类用来向其他对象注入
package com.di;
import org.springframework.stereotype.Component;
@Component
public class Teacher {
private String name = "韩梅梅";
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
'}';
}
}
创建一个Student类需要将Teacher注入到Student对象中
package com.di;
import org.springframework.stereotype.Component;
@Component
public class Student {
private String name="李雷";
//使用自定义注解标记注入对象
@MyAutowired
private Teacher teacher;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", teacher=" + teacher +
'}';
}
}
创建一个测试类实现对象的注入,
package com.di;
import org.junit.Test;
import java.lang.reflect.Field;
public class TestDI {
@Test
public void di() throws Exception {
//通过反射获取对象
Class s = Class.forName("com.di.Student");
//创建一个对象
Object o = s.newInstance();
//获取对象全部属性
Field[] fs = s.getDeclaredFields();
//遍历对象属性,拿到每一个属性
for (Field f : fs) {
//获取student中的注解
MyAutowired an = f.getAnnotation(MyAutowired.class);
//判断注解是否为空
if(an != null){
//需要将Teacher对象注入
f.setAccessible(true);
f.set(o,new Teacher());
}
}
System.out.println((Student)o);
}
}