JSON配置文件的數據結構:
package light.zhang.ioc.bean; import java.io.Serializable; import java.util.List; import lombok.Data; import lombok.ToString; /** * 數據結構 * @author witts */ @Data @ToString public class Beandefinition implements Serializable{ /** * 序列ID */
private static final long serialVersionUID = -1723354830429118453L; /**BeanName參數**/
private String beanName; private String className; private String interfaceName; private List<ConstructorArg> ConstructorArgs; private List<PropertyArg> PropertyArgs; }
參數注入類:
package light.zhang.ioc.bean; import java.io.Serializable; import lombok.Data; @Data public class ConstructorArg implements Serializable { private static final long serialVersionUID = -1094744504486782050L; private String ref; }
package light.zhang.ioc.bean; import java.io.Serializable; public class PropertyArg implements Serializable { private static final long serialVersionUID = 4398781604716858284L; }
讀取json配置文件:
package light.zhang.ioc.client; import java.io.InputStream; import java.util.List; import com.fasterxml.jackson.core.type.TypeReference; import light.zhang.ioc.bean.Beandefinition; import light.zhang.ioc.core.ApplicationContextFactory; import light.zhang.ioc.utils.JsonUtils; /** * 通過json格式的方式來存儲注冊信息,然后讓IOC容器管理對象 * @author witts */
public class JsonApplicationContext extends ApplicationContextFactory { private String fileName; public JsonApplicationContext(String fileName) { this.fileName = fileName; initFile(); } private void initFile(){//讀取文件,並注冊到容器
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);//讀取配置文件信息
List<Beandefinition> beanDefinitions = JsonUtils.readValue(is,new TypeReference<List<Beandefinition>>(){}); if(beanDefinitions != null && !beanDefinitions.isEmpty()) { for (Beandefinition beanDefinition : beanDefinitions) { registerBean(beanDefinition.getBeanName(), beanDefinition);//注冊
} } } }
通過名稱得到bean:
package light.zhang.ioc.core; import light.zhang.ioc.exception.CreateBeanException; import light.zhang.ioc.exception.LoadBeanException; public interface ApplicationContext { /** * 通過bean獲取到注冊的實例信息 * @param name * @throws Exception * @throws LoadBeanException * @throws CreateBeanException */
public Object getBean(String name) throws IllegalAccessException; }
負責bean生命周期管理,加載-實例-注冊-銷毀等
package light.zhang.ioc.core; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import light.zhang.ioc.bean.Beandefinition; import light.zhang.ioc.bean.ConstructorArg; import light.zhang.ioc.exception.CreateBeanException; import light.zhang.ioc.exception.LoadBeanException; import light.zhang.ioc.utils.BeanUtils; import light.zhang.ioc.utils.ClassLoaderUtils; import light.zhang.ioc.utils.ReflectionUtils; /** * 主要負責對加載到Map里面的對象取舍 beanDefineMap 存儲的是對象的名稱和對象對應的數據結構的映射。bean 用於保存 * beanName和實例化之后的對象。 容器初始化的時候,會調用 BeanRegisterFactoryImpl.registerBean 方法。把 * 對象的 Beandefinition 數據結構,存儲起來 當我們調用 getBean() 的方法的時候。會先到 beanMap * 里面查找,有沒有實例化好的對象。如果沒有, 就會去beanDefineMap查找這個對象對應的 * BeanDefination。再利用DeanDefination去實例化一個對象。 對象實例化成功以后,我們還需要注入相應的參數,調用 * populatebean()這個方法。在 populateBean 這個方法中, 會掃描對象里面的Field,如果對象中的 Field * 是我們IoC容器管理的對象,那就會調用 我們上文實現的 ReflectionUtils.injectField來注入對象。 * 一切准備妥當之后,我們對象就完成了整個 IoC 流程。最后這個對象放入 beanMap 中,方便下一次使用。 所以我們可以知道 BeanFactory 是管理和生成對象的地方。 */
public class ApplicationContextFactory implements ApplicationContext { private static final Logger logger=LoggerFactory.getLogger(ApplicationContextFactory.class); private static final ConcurrentHashMap<String, Object> beanMap = new ConcurrentHashMap<String, Object>(); private static final ConcurrentHashMap<String, Beandefinition> undefineMap = new ConcurrentHashMap<String, Beandefinition>(); private static final Set<Object> beanNameSet = Collections.synchronizedSet(new HashSet<Object>());// 同步的hash set
@Override public Object getBean(String name) throws IllegalAccessException { Object bean = null; bean = beanMap.get(name);// 在已經注冊過的情況下通過名稱獲取注冊的實例
if (null != bean) { return bean; } bean = createBean(undefineMap.get(name)); // 如果沒有實例化,那就需要調用createBean來創建對象,第一次加載的情況
if (bean != null) { // 對象創建成功以后,注入對象需要的參數
populatebean(bean); // 再把對象存入Map中方便下次使用。
beanMap.put(name, bean); } // 結束返回
logger.debug("This "+name+" is managed by ioc!!!"); return bean; } /** * 注冊bean到IOC容器里面 * * @param name * @param bean */
protected void registerBean(String name, Beandefinition bean) { undefineMap.put(name, bean);// 先注冊
beanNameSet.add(name);// 添加注冊信息
} /** * 主要負責對參數的初始化 * * @param bean * @throws IllegalAccessException * @throws Exception * @throws LoadBeanException * @throws CreateBeanException */
private void populatebean(Object bean) throws IllegalAccessException { Field[] fields = bean.getClass().getSuperclass().getDeclaredFields();// 獲取的代理對象信息
if (fields != null && fields.length > 0) {// 存在代理對象
for (Field field : fields) { String beanName = field.getName(); beanName = StringUtils.uncapitalize(beanName);// beanName字符串的第一個字符,轉換為小寫
if (beanNameSet.contains(field.getName())) {// 當包從IOC容器檢測到注冊信息之后
Object fieldBean = getBean(beanName);// 獲取實例
if (fieldBean != null) { ReflectionUtils.initParamter(field, bean, fieldBean);// 初始化參數信息
} } } } } /** * 創建bean實例 * * @param beanDefinition * @return * @throws IllegalAccessException * @throws LoadBeanException * @throws Exception */
private Object createBean(Beandefinition beanDefinition) throws IllegalAccessException { if(null == beanDefinition) { try { throw new CreateBeanException(); } catch (CreateBeanException e) { e.printStackTrace(); } } String beanName = beanDefinition.getClassName(); Class<?> classInfo = ClassLoaderUtils.loaderClass(beanName); if (classInfo == null) { try { throw new LoadBeanException(); } catch (LoadBeanException e) { e.printStackTrace(); } } List<ConstructorArg> constructorArgs = beanDefinition.getConstructorArgs();// 獲取參數列表
if (constructorArgs != null && !constructorArgs.isEmpty()) { List<Object> objects = new ArrayList<Object>(); for (ConstructorArg constructorArg : constructorArgs) { objects.add(getBean(constructorArg.getRef()));// ref引用信息
} try { return BeanUtils.instanceCreate(classInfo, classInfo.getConstructor(), objects.toArray());// 有參數的注入
} catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } } else { return BeanUtils.instanceCreate(classInfo, null, null);// 沒有參數
} return null; } }
創建對象時異常
package light.zhang.ioc.exception; /** * 創建時異常 * @author witts * */
public class CreateBeanException extends Throwable { private static final long serialVersionUID = 1L; public CreateBeanException() { super("create bean fail,bean name is not found!!!"); } /** * 創建bean異常 * @param exc */
public CreateBeanException(String exc) { super(exc); } }
加載bean異常
package light.zhang.ioc.exception; /** * 加載時異常 * @author witts */
public class LoadBeanException extends Throwable{ private static final long serialVersionUID = 8520827571307312752L; @Override public synchronized Throwable fillInStackTrace() { return super.fillInStackTrace(); } public LoadBeanException() { super("load bean exception,bean not found!!!"); } public LoadBeanException(String message) { super(message); } }
bean工具類:
package light.zhang.ioc.utils; import java.lang.reflect.Constructor; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.NoOp; /** * 主要負責處理對BEAN的管理,BEAN的初創建,始化,狀態管理 * @author witts */
public class BeanUtils { /** * 動態代理,並創建類 * @param clas * @param constructor * @param args * @return
*/
public static Object instanceCreate(Class<?> clas,Constructor<?> constructor,Object[] args) { /** * Enhancer允許為非接口類型創建一個Java代理。Enhancer動態創建了給定類型的子類但是攔截了所有的方法。和Proxy不一樣的是,不管是接口還是類他都能正常工作 */ Enhancer enhancer=new Enhancer(); enhancer.setSuperclass(clas);//代理類
enhancer.setCallback(NoOp.INSTANCE);//代理類型>初始化實例
if(null == constructor) { return enhancer.create();//默認創建無參數實例
}else { return enhancer.create(constructor.getParameterTypes(),args);//帶參數的初始化
} } }
類裝載工具類:
package light.zhang.ioc.utils; /** * 主要負責讀取配置文件,裝載類信息 * @author witts * */
public class ClassLoaderUtils { /**創建讀取配置信息的對象**/
public static ClassLoader install() { return Thread.currentThread().getContextClassLoader(); } /**裝載class**/
public static Class<?> loaderClass(String className) { try { return install().loadClass(className);//通過配置文件裝載類信息
}catch (ClassNotFoundException e) { e.printStackTrace(); } return null; } }
json工具類:
package light.zhang.ioc.utils; import java.io.InputStream; import java.text.SimpleDateFormat; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; public class JsonUtils { private static final ObjectMapper mapper = new ObjectMapper(); private JsonUtils() { } public static ObjectMapper getObjectMapper() { return mapper; } public static <T> T readValue(String json, Class<T> cls) { try { return mapper.readValue(json, cls); } catch (Exception var3) { return null; } } public static <T> T readValue(InputStream is,Class<T> cls){ try{ return mapper.readValue(is,cls); }catch (Exception e){ return null; } } public static <T> T readValue(byte[] bytes, Class<T> cls) { try { return mapper.readValue(bytes, cls); } catch (Exception var3) { return null; } } public static <T> T readValue(String json, TypeReference<?> valueTypeRef) { try { return mapper.readValue(json, valueTypeRef); } catch (Exception var3) { return null; } } public static <T> T readValue(byte[] bytes, TypeReference<?> valueTypeRef) { try { return mapper.readValue(bytes, valueTypeRef); } catch (Exception var3) { return null; } } public static <T> T readValue(InputStream is,TypeReference<?> valueTypeRef){ try{ return mapper.readValue(is,valueTypeRef); }catch (Exception e){ return null; } } public static String writeValue(Object entity) { try { return mapper.writeValueAsString(entity); } catch (Exception var2) { return null; } } public static byte[] writeByteValue(Object entity) { try { return mapper.writeValueAsBytes(entity); } catch (Exception var2) { return null; } } static { mapper.enable(SerializationFeature.INDENT_OUTPUT); mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); mapper.setSerializationInclusion(JsonInclude.Include.USE_DEFAULTS); mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); mapper.getDeserializationConfig().withoutFeatures(new DeserializationFeature[]{DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES}); mapper.configure(MapperFeature.ALLOW_COERCION_OF_SCALARS, true); mapper.configure(MapperFeature.ALLOW_EXPLICIT_PROPERTY_RENAMING,true); mapper.configure(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS, true); mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } }
反射類:
package light.zhang.ioc.utils; import java.lang.reflect.Field; /** * 主要通過 Java 的反射原理來完成對象的信息注入 * @author witts */
public class ReflectionUtils { /** * 初始化參數信息 * @param field * @param key * @param val * @throws IllegalAccessException */
public static void initParamter(Field field,Object key,Object val) throws IllegalAccessException { if(null !=field) { field.setAccessible(Boolean.TRUE); field.set(key, val);//注入參數信息
} } }
客戶端調用
package light.zhang.ioc.test; import junit.framework.TestCase; import light.zhang.ioc.client.JsonApplicationContext; import light.zhang.ioc.core.ApplicationContext; /** * 模擬spring ioc對象創建管理銷毀 * @author witts * */
public class AppTest extends TestCase { private static final ApplicationContext applicationContext=new JsonApplicationContext("application.json"); //讀取配置文件
public static void main(String[] args) { try { Robot aiRobot; aiRobot = (Robot) applicationContext.getBean("robot");//獲取對象
aiRobot.show();//調用對象功能
} catch (Exception e) { e.printStackTrace(); } } }
需要被管理的對象
package light.zhang.ioc.test; public class Hand { public void waveHand(){ System.out.println("hand out message"); } }
package light.zhang.ioc.test; public class Mouth { public void speak(){ System.out.println("Mouth out message"); } }
package light.zhang.ioc.test; public class Robot { //需要注入 hand 和 mouth,容器自動注入對象並實例化
private Hand hand; private Mouth mouth; public void show(){ hand.waveHand(); mouth.speak(); } }
主要是理解spring ioc的加載-實例-注冊-銷毀等一系列的對象生命周期管理,我這里只是模仿一下spring對對象的加載,創建,注冊 對象銷毀是個復雜的過程,並不是那么容器就模擬出來的,
spring管理的對象方式有很多種,
本來是由應用程序管理的對象之間的依賴關系,現在交給容器管理,這就是控制反轉,及交給Ioc容器。Spring的IoC主要使用DI方式實現,
不需要主動查找,對象的查找、定位和創建全部由容器管理。spring中有三種注入方式,一種是set注入,一種是接口注入,另一種是構造方法注入