IOC 控制反转
其实spring底层用的是工厂设计模式,
下面逐步实现控制反转。
案列
- 目录结构
在包com.westos2.ioc下新建
- ATest类
- BTest类,类中属性有ATest aTest;
需求生产一个A对象,生产一个B对象(内包含A)。
- 代码ATest
package com.westos2.ioc;
public class ATest {
public void show(){
System.out.println("我是A");
}
}
- 代码BTest
package com.westos2.ioc;
public class BTest {
private ATest aTest;
public ATest getaTest() {
return aTest;
}
public void setaTest(ATest aTest) {
this.aTest = aTest;
}
public void show(){
System.out.println("我是B,我准备调用A.show()");
aTest.show();
}
@Override
public String toString() {
return "BTest{" +
"aTest=" + aTest +
'}';
}
}
- ClassBean类,用于封装要创建实例类的信息
package com.westos2.ioc;
import java.util.Map;
public class ClassBean {
private String name;
private String id;
private Map<String,Object> map;
public ClassBean() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Map<String, Object> getMap() {
return map;
}
public void setMap(Map<String, Object> map) {
this.map = map;
}
@Override
public String toString() {
return "ClassBean{" +
"name='" + name + '\'' +
", id='" + id + '\'' +
", map=" + map +
'}';
}
}
Main类,用于创建对象,并测试代码
package com.westos2.ioc;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Main {
//用于存储创建好的对象
private static Map<String,Object> content =new HashMap<>();
public static void main(String[] args) {
//封装ATest类信息
ClassBean classBean = new ClassBean();
classBean.setId("a");
classBean.setName("com.westos2.ioc.ATest");
System.out.println(classBean);
//封装BTest类信息
ClassBean classBean2 = new ClassBean();
classBean2.setId("b");
classBean2.setName("com.westos2.ioc.BTest");
Map<String, Object> map = new HashMap<>();
//ATest表示属性名,a代表ATest类的id
map.put("aTest","a");
classBean2.setMap(map);
System.out.println(classBean2);
//创建ATest对象
ATest o = (ATest)create(classBean);
System.out.println("A对象:"+o);
//创建BTest对象,此时BTest中的属性aTest还是null
BTest o1 = (BTest) create(classBean2);
System.out.println("B对象:"+o1);
//装配对象BTest中的属性aTest
createb(classBean2, content);
System.out.println("装配后的B对象:"+o1);
}
public static Object create(ClassBean classBean){
Object o;
try {
Class<?> aClass = Class.forName(classBean.getName());
o = aClass.newInstance();
//将已经创建好的存起来
content.put(classBean.getId(),o);
return o;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void createb(ClassBean classBean,Map content){
Map<String, Object> map = classBean.getMap();
//如果类中有属性
if (map!=null){
Set<String> keys = map.keySet();
for (String key : keys) {
//给类中属性设值
//content.get(classBean.getId())拿到目标类对象,即BTest
//content.get(map.get(key)),用map中属性名对应的值(ATest类的id)拿到ATest对象
//key属性名,用于下面方法中找到对应的set方法
invoke(content.get(classBean.getId()),content.get(map.get(key)),key);
}
}
}
private static void invoke(Object tagert,Object value,String name) {
Method[] methods = tagert.getClass().getMethods();
//注意set方法名的大小写问题。
String methodsName="set"+name;
//System.out.println(methodsName);
Method method1=null;
for (Method method : methods) {
if (method.getName().equals(methodsName)){
method1=method;
}
}
try {
//给目标类(BTest)的属性aTest设置值
method1.invoke(tagert,new Object[]{value});
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
改进版
-
上述代码是用ClassBean封装类的信息,现在用配置文件封装。
-
上述代码复制一份放在ioc2包下
-
Main类变化如下,其他不变
package com.westos2.ioc2;
import com.alibaba.fastjson.JSON;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Main {
private static Map<String, Object> content = new HashMap<>();
public static void main(String[] args) throws Exception {
init();
Map<String, Object> factory = getFactory();
ATest a = (ATest) factory.get("a");
a.show();
BTest b = (BTest) factory.get("b");
b.getaTest().show();
}
public static Map<String,Object> getFactory(){
return content;
}
public static void init() throws Exception {
String s = System.getProperty("user.dir");
//建一个json文件,放在maven项目的resources下为例
InputStream in=new FileInputStream(new File("E:\\mavenProject\\_20190519dynastryproxy\\src\\main\\resources\\ioc.json"));
//common-io jar包
String s1 = IOUtils.toString(in, "utf-8");
//json解析成ClassBean对象集合。
List<ClassBean> classBeans = JSON.parseArray(s1, ClassBean.class);
//遍历创建对象
for (ClassBean classBean : classBeans) {
content.put(classBean.getId(),create(classBean));
}
//遍历装配
for (ClassBean classBean : classBeans) {
createb(classBean,content);
}
}
public static Object create(ClassBean classBean) {
Object o;
try {
Class<?> aClass = Class.forName(classBean.getName());
o = aClass.newInstance();
content.put(classBean.getId(), o);
return o;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void createb(ClassBean classBean, Map content) {
Map<String, Object> map = classBean.getMap();
if (map != null) {
Set<String> keys = map.keySet();
for (String key : keys) {
invoke(content.get(classBean.getId()), content.get(map.get(key)), key);
}
}
}
private static void invoke(Object tagert, Object value, String name) {
Method[] methods = tagert.getClass().getMethods();
String methodsName = "set" + name;
Method method1 = null;
for (Method method : methods) {
if (method.getName().equals(methodsName)) {
method1 = method;
}
}
try {
method1.invoke(tagert, new Object[]{value});
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
- ioc.json
[
{
"id": "a",
"name": "com.westos2.ioc2.ATest"
},
{
"id": "b",
"map": {
"aTest": "a"
},
"name": "com.westos2.ioc2.BTest"
}
]
spring下ioc的使用
-
新建一个westos3.springioc包,将上面的ATest和BTest复制一下,
-
SpringUtils类
package com.westos3.springioc;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringUtils {
public static ApplicationContext context=null;
static {
//初始化spring,读取配置文件,maven项目,resources下的spring.xml
context = new ClassPathXmlApplicationContext("spring.xml");
}
private SpringUtils() {
}
public static ApplicationContext getContext() {
return context;
}
}
- Test类
package com.westos3.springioc;
public class Test {
public static void main(String[] args) {
BTest b = (BTest)SpringUtils.getContext().getBean("b");
b.getaTest().show();
}
}
resources目录下(与java文件夹平级)的spring.xml
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
">
<bean id="a" class="com.westos3.springioc.ATest"/>
<bean id="b" class="com.westos3.springioc.BTest">
<property name="aTest" ref="a"/>
</bean>
</beans>
谢谢!