模拟IOC
- BeanFactory
package org.spring.util;
import com.luban.service.UserService;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.*;
public class BeanFactory {
/**
*
*/
Map<String, Object> map = new HashMap<String, Object>();
public BeanFactory(String xml) {
parseXml(xml);
}
public void parseXml(String xml) {
File file = new File(this.getClass().getResource("/").getPath() + "//" + xml);
SAXReader reader = new SAXReader();
try {
Document document = reader.read(file);
Element root = document.getRootElement();
// List<Element> allChild = root.elements();
Attribute default_autowire = root.attribute("default-autowire");
boolean flag = false;
//判断根据什么自动装配,若为空,则说明是根据byName
if (default_autowire != null) {
//不为空
flag = true;
}
// 第一层Bean
for (Iterator<Element> itFirst = root.elementIterator(); itFirst.hasNext(); ) {
/**
* 第一步。实例化对象
*/
Element elementFirstChild = itFirst.next();
Attribute attributeID = elementFirstChild.attribute("id"); //属性,beanName
String beanName = attributeID.getValue();
Attribute attributeClass = elementFirstChild.attribute("class");//获取全类名,具体的类
String className = attributeClass.getValue();
Class<?> classzz = Class.forName(className);//获取类对象
/**
* 维护依赖关系
* 看这个对象有没有依赖(判断是否有有property, 或者判断类是否有属性)
* 就是给类对象中注入值
*/
//第二层,依赖关系
Object object = null;//实例化对象的变量,判断是否有依赖在进行实例化
for (Iterator<Element> itSecond = elementFirstChild.elementIterator(); itSecond.hasNext(); ) {
/**
* <property name="dao" ref="dao"></property>
* 得到ref的value,通过value得到对象(map)
* 得到的name的值,然后根据值获取一个Filed的对象
* 通过field的set方法set那个对象
*
*/
Element elementSecondeChild = itSecond.next();
//setter注入,就是给属性值赋值
if (elementSecondeChild.getName().equals("property")) { //property就是setter注入方式,本来应该是根据stter后的名称注入,但是这里是采用属性的名称注入的方式
object = classzz.newInstance();//实例化bean UserServiceImp
String refValue = elementSecondeChild.attribute("ref").getValue(); //获取依赖的类的对象
Object injectObject = map.get(refValue);//获取实例对象
String nameValue = elementSecondeChild.attribute("name").getValue(); //这里本来是要执行set+"name"的方法,但是简单做法,直接给成员变量赋值
Field field = classzz.getDeclaredField(nameValue);//类对象里面的值变量
if (field == null) {
throw new NoFieldException("类中没有这个属性");
}
field.setAccessible(true);
field.set(object, injectObject);//(obj,value) object(对象UserServiceImp对象)的成员变量field(UserDao) = injectObject(map中已经实例化的对象UserDao)
} else if(elementSecondeChild.getName().equals("constructor-arg")){
//构造方法注入
//获取构造方法里面的成员变量(属性)
// Attribute name = elementSecondeChild.attribute("name");
// Constructor constructor = classzz.getConstructor(name.getClass());
// String refValue = elementSecondeChild.attribute("ref").getValue(); //获取依赖的类的对象
// Object injectObject = map.get(refValue);//获取实例对象
// object = constructor.newInstance(injectObject);
String refValue = elementSecondeChild.attribute("ref").getValue();
Object injectObject = map.get(refValue);
Class injectObjectClass = injectObject.getClass();
Constructor constructor = classzz.getConstructor(injectObjectClass.getInterfaces()[0]); //根据接口注入 UserDao, 获取类之后还要获取接口
object = constructor.newInstance(injectObject);
}
else{
throw new NoSuchElementException("没有这个属性");
}
}
if (object == null) { //byName优先,byType后面
if (flag) {
if (default_autowire.getValue().equals("byType")) { //class类型
//判断是否有依赖,就是判断有没有属性
Field[] declaredFields = classzz.getDeclaredFields();
for (Field declaredField : declaredFields) {
Class<?> injectObjectClass = declaredField.getType();
/**
* 由于是bytype 所以需要便利map当中的所有对象
* 判断对象的类型是不是和这个injectObjectClass相同
*/
int count = 0;
Object injectObject = null;
for (String key : map.keySet()) {
Class temp = map.get(key).getClass().getInterfaces()[0];
if (temp.getName().equals(injectObjectClass.getName())) {
injectObject = map.get(key);
count++;
}
}
if (count > 1) {
throw new TooManyObjectException("需要一个对象,但是找到了多个对象");
} else {
/**
* 必须要有无参构造函数或者默认构造函数才可以运行
*/
object = classzz.newInstance(); //对象
declaredField.setAccessible(true);
declaredField.set(object, injectObject);
}
}
}
}
}
//没有子标签
if (object == null) {
object = classzz.newInstance();
}
map.put(beanName, object);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(map);
}
public Object getBean(String beanName) {
return map.get(beanName);
}
}
package org.spring.util;
public class NoFieldException extends RuntimeException {
public NoFieldException(String str){
super(str);
}
}
package org.spring.util;
public class TooManyObjectException extends RuntimeException {
public TooManyObjectException(String msg){
super(msg);
}
}
- dao
package com.luban.dao;
public interface UserDao {
public void query();
}
package com.luban.dao;
public class UserDaoImp implements UserDao{
@Override
public void query() {
System.out.println("UserDao1");
}
}
package com.luban.dao;
public class UserDaoImp2 implements UserDao{
@Override
public void query() {
System.out.println("UserDao2");
}
}
- service
package com.luban.service;
import com.luban.dao.UserDao;
//代理
public interface UserService {
public void find();
}
//代理实现
public class UserServiceImp implements UserService {
UserDao propertydao;
@Override
public void find() {
System.out.println("service");
propertydao.query();
}
public void setDao(UserDao dao) { //装饰者模式
this.propertydao = dao;
}
}
package com.luban.test;
import com.luban.dao.UserDao;
import com.luban.service.UserService;
import com.luban.service.UserServiceImp;
import org.spring.util.BeanFactory;
public class Test {
public static void main(String[] args) {
BeanFactory beanFactory = new BeanFactory("spring.xml");
UserService service = (UserService) beanFactory.getBean("service");
service.find();
}
}
模拟AOP
申明一个Bean,有三种办法:
- XML配置()
- @Component(注解)
- Java Config(@Bean,或者扫描)
package com.luban.anno;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com")
public class SpringConfig {
}
package com.luban.dao;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;
/**
*
* 如果你的类实现了FactoryBean
* 那么Spring容器当中存在两个对象
* 一个叫是getObject()返回的对象
* 还有一个是当前对象(daoFactoryBean)
*
* getObject得到的对象存的是当前类指定的名字
* 当前对象是“&”+但前的名字
*
*/
@Component("daoFactoryBean")
public class DaoFactoryBean implements FactoryBean {
public void func(){
System.out.println("DaoFactoryBean");
}
@Override
public Object getObject() throws Exception {
return new TestFactoryBean();
}
@Override
public Class<?> getObjectType() {
return TestFactoryBean.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
@Component("testFactoryBean")
public class TestFactoryBean {
public void func(){
System.out.println("testFactoryBean");
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
TestFactoryBean daoFacrotyBean = (TestFactoryBean) annotationConfigApplicationContext.getBean("daoFactoryBean");
daoFacrotyBean.func();
}
}
根据结果可以知道取得Bean的名字是"daoFactoryBean",给的类型却是TestFactoryBean.
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
DaoFactoryBean daoFacrotyBean = (DaoFactoryBean) annotationConfigApplicationContext.getBean("&daoFactoryBean");
daoFacrotyBean.func();
}
}
FactoryBean: 当引用第三方的类时,第三方类中有很多其他的属性,我们就使用FactoryBean(简化配置)(也是一个Bean, 造Bean )
BeanFactory:Bean工厂,管理Bean
初始化Spring的环境有几种办法:
xml ClassPathXmlApplicationContext 类的扫描 单独bean的注册(声明和注册)
annotation
javaconfig AnnotationConfigApplication 类的扫描 类的定义(没有类的注册)
注册Bean(@Bean, <bean>, register(需要refresh),@Autowired, @Component )
所谓的初始化spring环境—>把我们交给spring管理的类实例化
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext =
new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.refresh(SpringConfig.class);
annotationConfigApplicationContext.register(Userdao.class);
annotationConfigApplicationContext.refresh();
}
}
自定义扫描注解
@Retention(RetentionPolicy.RUNTIME) //一定要加上,否则运行时会忽略
public @interface Luban {
public String value();
}
@Luban("service")
public class UserServiceImp implements UserService {
}
public class AnnotationConfigApplicationContext {
//最终得到类(Object)
public void scan(String basePackage){
String rootPath = this.getClass().getResource("/").getPath();
String basePackagePath = basePackage.replaceAll("\\.","\\\\");
File file = new File(rootPath +"//" + basePackagePath);
String names[] = file.list();
for (String name : names) {
name = name.replaceAll(".class","");
try {
Class clazz = Class.forName(basePackage + "." + name);
if(clazz.isAnnotationPresent(Luban.class)){
Luban luban = (Luban) clazz.getAnnotation(Luban.class);
System.out.println(luban.value());
System.out.println(clazz.newInstance());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext =
new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.scan("com.luban.service");
}
}