IOC是什么
- IOC:控制反转,是一种设计模式。
- 一层含义是控制权的转移,由传统的在程序中控制依赖转移到由容器来控制。
- 第二层是依赖注入:将相互依赖的对象分离,在Spring配置文件中描述他们的依赖关系,他们的依赖关系只在使用的时候才建立,简单来说就是不需要的NEW一个对象了。
BeanFactory
BeanFactory,以Factory结尾,表示它是一个工厂类(接口), 它负责生产和管理bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。
原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。ApplicationContext接口,它由BeanFactory接口派生而来。现在一般使用ApplicationnContext,其不但包含了BeanFactory的作用,同时还进行更多的扩展
Note:BeanFactory和ApplicationContext创建Bean的区别
BeanFactory | 延时加载,在使用到某个Bean时才会进行实例化Bean |
ApplicationConetxt | 在ApplicationContext对象创建时,会立即实例化单例Bean以及其依赖 |
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="com.lb.springioc.dao.UserDaoImpl"></bean>
<bean id="userService" class="com.lb.springioc.service.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
</beans>
Bean加载原理
BeanDefinition | 对应配置文件中的<bean>标签 |
BeanDefinitionReader | 读取配置文件所有的BeanDefinition |
BeanDefinitionRegistry | 将Reader读取到的BeanDefinition放在容器中 |
BeanDefinition
BeanDefinitionHolder就是持有对bean标签读取到的信息的对象
BeanDefinitionReader
BeanDefinitionRegistry
自实现的IOC
依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
实体类
@Data
public class BeanDefinition {
private String id;
private String className;
private PropertyValues propertyValues;
public BeanDefinition() {
propertyValues = new PropertyValues();
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PropertyValue {
private String name;
private String ref;
private String value;
}
public class PropertyValues implements Iterable<PropertyValue> {
private List<PropertyValue> list;
public PropertyValues() {
list = new ArrayList<>();
}
public PropertyValues add(PropertyValue propertyValue) {
for (int i = 0; i < list.size(); i++) {
PropertyValue value = list.get(i);
if (value.getName().equals(propertyValue.getName())) {
list.set(i, propertyValue);
return this;
}
}
list.add(propertyValue);
return this;
}
public PropertyValue[] getPropertyValues() {
return list.toArray(new PropertyValue[0]);
}
public PropertyValue geTPropertyValue(String name) {
for (int i = 0; i < list.size(); i++) {
PropertyValue value = list.get(i);
if (value.getName().equals(name)) {
return value;
}
}
return null;
}
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public Iterator<PropertyValue> iterator() {
return list.iterator();
}
}
Reader & Registry
public interface BeanDefinitionReader {
BeanDefinitionRegistry getRegistry();
void loadResource(String location) throws Exception;
}
public class XmlBeanDefinitionReader implements BeanDefinitionReader {
private BeanDefinitionRegistry registry;
public XmlBeanDefinitionReader() {
registry = new SimpleBeanDefinitionRegistry();
}
@Override
public BeanDefinitionRegistry getRegistry() {
return registry;
}
@Override
public void loadResource(String location) throws Exception {
SAXReader reader = new SAXReader();
InputStream inputStream = XmlBeanDefinitionReader.class.getClassLoader().getResourceAsStream(location);
Document document = reader.read(inputStream);
Element rootElement = document.getRootElement();
List<Element> beans = rootElement.elements("bean");
for (Element bean : beans) {
BeanDefinition beanDefinition = new BeanDefinition();
String id = bean.attributeValue("id");
beanDefinition.setId(id);
beanDefinition.setClassName(bean.attributeValue("class"));
PropertyValues values = new PropertyValues();
List<Element> properties = bean.elements("property");
for (Element property : properties) {
PropertyValue value = new PropertyValue();
value.setName(property.attributeValue("name"));
value.setRef(property.attributeValue("ref"));
value.setValue(property.attributeValue("value"));
values.add(value);
}
beanDefinition.setPropertyValues(values);
registry.registerBeanDefinition(id, beanDefinition);
}
}
}
public interface BeanDefinitionRegistry {
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);
void removeBeanDefinition(String beanName) throws Exception;
BeanDefinition getBeanDefinition(String beanName);
boolean containsBeanDefinition(String beanName);
String[] getBeanDefinitionNames();
int getBeanDefinitionCount();
}
public class SimpleBeanDefinitionRegistry implements BeanDefinitionRegistry {
private Map<String, BeanDefinition> map = new HashMap<String, BeanDefinition>();
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
map.put(beanName, beanDefinition);
}
@Override
public void removeBeanDefinition(String beanName) throws Exception {
map.remove(beanName);
}
@Override
public BeanDefinition getBeanDefinition(String beanName) {
return map.get(beanName);
}
@Override
public boolean containsBeanDefinition(String beanName) {
return map.containsKey(beanName);
}
@Override
public String[] getBeanDefinitionNames() {
return map.keySet().toArray(new String[0]);
}
@Override
public int getBeanDefinitionCount() {
return map.size();
}
}
BeanFacoty & ApplicationContext
/**
* 提供BeanFactory的主要功能获取Bean
*/
public interface BeanFactory {
Object getBean(String beanName) throws Exception;
<T> T getBean(String beanName, Class<? extends T> clazz) throws Exception;
}
/**
* 所有的子类对bean的创建都是非延时的
*/
public interface ApplicationContext extends BeanFactory {
/**
* 加载配置文件,并创建对象
* @throws Exception
*/
void refresh() throws Exception;
}
public abstract class AbstractApplicationContext implements ApplicationContext {
protected Map<String, Object> singletonMaps = new HashMap<>();
protected BeanDefinitionReader beanDefinitionReader;
protected String configLocation;
@Override
public void refresh() throws Exception {
beanDefinitionReader.loadResource(configLocation);
//初始化所有的bean
initializationBean();
}
private void initializationBean() throws Exception {
BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
String[] beanDefinitionNames = registry.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = registry.getBeanDefinition(beanDefinitionName);
getBean(beanDefinition.getId());
}
}
}
public class ClassPathXmlApplicationContext extends AbstractApplicationContext {
public ClassPathXmlApplicationContext(String location) {
this.configLocation = location;
this.beanDefinitionReader = new XmlBeanDefinitionReader();
try {
refresh();
} catch (Exception e) {
}
}
@Override
public Object getBean(String beanName) throws Exception {
Object obj = singletonMaps.get(beanName);
if (obj != null) {
return obj;
}
BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
String clazzName = beanDefinition.getClassName();
Class<?> clazz = Class.forName(clazzName);
Object bean = clazz.newInstance();
PropertyValues propertyValues = beanDefinition.getPropertyValues();
for (PropertyValue propertyValue : propertyValues) {
//拼接set方法
String name = propertyValue.getName();
String setMethodName = StrUtil.filedName2SetMethodName(name);
Method[] methods = clazz.getMethods();
Method method = null;
for (Method m : methods){
if (m.getName().equals(setMethodName)){
method = m;
break;
}
}
//反射创建对象
String refStr = propertyValue.getRef();
if (null != refStr && !"".equals(refStr)) {
Object refObj = getBean(refStr);
method.invoke(bean, refObj);
}
//value是赋值的
String value = propertyValue.getValue();
if (null != value && !"".equals(value)) {
method.invoke(bean, value);
}
}
singletonMaps.put(beanName, bean);
return bean;
}
@Override
public <T> T getBean(String beanName, Class<? extends T> clazz) throws Exception {
Object obj = getBean(beanName);
if (obj == null) return null;
return clazz.cast(obj);
}
}
测试
将上面的项目打包,测试项目引入其依赖
<dependency>
<groupId>com.test</groupId>
<artifactId>mySpring</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
测试代码:
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="springioc.dao.UserDaoImpl"></bean>
<bean id="userService" class="springioc.service.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
</beans>
import com.lb.context.ClassPathXmlApplicationContext;
import springioc.dao.UserDao;
import springioc.service.UserService;
public class UserController {
public static void main(String[] args) throws Exception{
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = classPathXmlApplicationContext.getBean("userDao", UserDao.class);
UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);
System.out.println(userDao);
System.out.println(userService);
userService.add();
}
}
测试结果: