怎樣建設(shè)網(wǎng)站公司百度app關(guān)鍵詞優(yōu)化
目錄
一、什么是 Spring IOC?
二、IOC 的作用
1. IOC 怎么知道要?jiǎng)?chuàng)建哪些對(duì)象呢?
2. 創(chuàng)建出來(lái)的對(duì)象放在哪兒?
3. 創(chuàng)建出來(lái)的對(duì)象如果有屬性,如何給屬性賦值?
三、實(shí)現(xiàn)步驟
1. 創(chuàng)建自定義注解
2. 創(chuàng)建 IOC 容器
1. 創(chuàng)建 Bean 定義類
2. 創(chuàng)建 IOC 容器
3. 掃描包
4. 使用自定義注解
5. 在 Servlet 中初始化 IOC 對(duì)象
6. 測(cè)試
3. 實(shí)例化 Bean?
測(cè)試
4. 設(shè)置屬性
1. 創(chuàng)建一個(gè)Controller
2. 屬性賦值
3. 測(cè)試
四、使用 Bean
1. 創(chuàng)建獲取 Bean 的方法
2. 使用 Bean?
3. 測(cè)試
五、優(yōu)化 IOC 容器
一、什么是 Spring IOC?
Spring 的核心之一是 IOC,全稱 Inversion Of Control ,控制反轉(zhuǎn),用來(lái)統(tǒng)一管理 Bean
二、IOC 的作用
IOC 的作用就是幫程序員創(chuàng)建 Bean 對(duì)象
1. IOC 怎么知道要?jiǎng)?chuàng)建哪些對(duì)象呢?
在 xml?配置文件中指定要?jiǎng)?chuàng)建哪些對(duì)象,或者使用注解的方式
如果使用注解的方式,需要自定義注解,自定義注解說(shuō)白了就是告訴 JVM 這個(gè) Bean 不同于其他普通的 Bean ,它有其他的用途,標(biāo)記一下。
@Component、@Controller、@Service 可以用于創(chuàng)建 Bean 的注解
2. 創(chuàng)建出來(lái)的對(duì)象放在哪兒?
先記錄需要被創(chuàng)建的 Bean 對(duì)象的信息,存到 HashMap 中,然后根據(jù) HashMap 中存儲(chǔ)的Bean 的信息創(chuàng)建對(duì)象,存到IOC容器中
3. 創(chuàng)建出來(lái)的對(duì)象如果有屬性,如何給屬性賦值?
使用注解 @Autowired
三、實(shí)現(xiàn)步驟
1. 創(chuàng)建自定義注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {String value() default "";
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {String value() default "";
}
2. 創(chuàng)建 IOC 容器
掃描包,判斷類上是否有注解,如果有,存儲(chǔ)需要被創(chuàng)建的對(duì)象的id,也就是全類名。
定義一個(gè)類用于存儲(chǔ)這些信息,這個(gè)類就是 BeanDefinition? 叫做 Bean 定義類,Bean 定義類創(chuàng)建對(duì)象后稱為 Bean 定義對(duì)象,這個(gè)對(duì)象存儲(chǔ)了 Bean 的信息
然后把 Bean 定義對(duì)象存放到 HashMap 中,這個(gè) Map 叫做 Bean 定義Map
1. 創(chuàng)建 Bean 定義類
package com.shao.IOC;public class BeanDefinition {private String id;private String className;public BeanDefinition() {}public BeanDefinition(String id, String className) {this.id = id;this.className = className;}/*** 獲取** @return id*/public String getId() {return id;}/*** 設(shè)置** @param id*/public void setId(String id) {this.id = id;}/*** 獲取** @return className*/public String getClassName() {return className;}/*** 設(shè)置** @param className*/public void setClassName(String className) {this.className = className;}public String toString() {return "BeanDefinition{id = " + id + ", className = " + className + "}";}
}
2. 創(chuàng)建 IOC 容器
3. 掃描包
掃描包需要先知道路徑是什么,從哪開(kāi)始
這里掃描的是編譯后的 class 文件,并不是類文件,因?yàn)槌绦蜻\(yùn)行后使用的是編譯后的文件
那如何從這里開(kāi)始呢?
使用類加載器獲取路徑
package com.shao.IOC;import com.shao.Annotation.Controller;
import com.shao.Annotation.Service;import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;/*** ApplicationContext 類. 當(dāng)作 IOC 容器** @author shao.*/
public class ApplicationContext {/*** Bean 定義Map 存儲(chǔ)Bean 定義對(duì)象*/private HashMap<String, BeanDefinition> beanDefinitionMap = new HashMap<>();/*** Bean 實(shí)例Map 存儲(chǔ)Bean 實(shí)例對(duì)象*/private HashMap<String, Object> BeanMap = new HashMap<>();public ApplicationContext(String basePackage) throws UnsupportedEncodingException {scanPackage(basePackage);}/*** 1. 掃描包,掃描需要被創(chuàng)建的類,創(chuàng)建 Bean 定義對(duì)象,并放入 Bean 定義Map中*/public void scanPackage(String basePackage) throws UnsupportedEncodingException {
// String basePackage = "com.shao";// 獲取類加載器ClassLoader classLoader = this.getClass().getClassLoader();// 獲取包路徑String path = classLoader.getResource(basePackage.replace(".", "/")).getPath();// 路徑解碼,如果路徑有空格或者中文,會(huì)出現(xiàn) 16 進(jìn)制的字符String packagePath = URLDecoder.decode(path, "UTF-8");// 創(chuàng)建文件對(duì)象File fileDir = new File(packagePath);// 獲取包下的文件列表File[] files = fileDir.listFiles();for (File file : files) {if (file.isFile()) {// 判斷是否是class文件if (file.getName().endsWith(".class")) {// 包路徑 + 文件名 構(gòu)成全類名String className = basePackage + "." + file.getName().replace(".class", "");try {// 動(dòng)態(tài)加載了名為 className 的類,獲取該類的 Class 對(duì)象Class<?> aClass = Class.forName(className);// 判斷該類是否有 @Service 或 @Controller 注解if (aClass.isAnnotationPresent(Service.class) ||aClass.isAnnotationPresent(Controller.class)) {System.out.println("需要?jiǎng)?chuàng)建:" + className);// 將該類的類名首字母小寫(xiě)作為 idString id = aClass.getSimpleName().substring(0, 1).toLowerCase() + aClass.getSimpleName().substring(1);System.out.println("id:" + id);// 創(chuàng)建 Bean 定義對(duì)象,并放入 Bean 定義Map中beanDefinitionMap.put(id, new BeanDefinition(id, className));}} catch (ClassNotFoundException e) {e.printStackTrace();}}} else if (file.isDirectory()) {// 遞歸掃描子文件夾String subPackagePath = basePackage + "." + file.getName();scanPackage(subPackagePath);}}}
}
4. 使用自定義注解
5. 在 Servlet 中初始化 IOC 對(duì)象
這里為了方便測(cè)試,所以先在?Servlet 中初始化 IOC?
6. 測(cè)試
3. 實(shí)例化 Bean?
遍歷 Bean 定義Map ,取出 Bean 定義對(duì)象,根據(jù)對(duì)象的信息使用反射技術(shù)創(chuàng)建 Bean 對(duì)象,這個(gè)時(shí)候這個(gè) Bean 也叫裸Bean,然后存入 Bean Map 中。這一步在 Bean 的生命周期中屬于 Bean 的實(shí)例化
package com.shao.IOC;import com.shao.Annotation.Controller;
import com.shao.Annotation.Service;import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;/*** ApplicationContext 類. 當(dāng)作 IOC 容器** @author shao.*/
public class ApplicationContext {/*** Bean 定義Map 存儲(chǔ)Bean 定義對(duì)象*/private HashMap<String, BeanDefinition> beanDefinitionMap = new HashMap<>();/*** Bean 實(shí)例Map 存儲(chǔ)Bean 實(shí)例對(duì)象*/private HashMap<String, Object> BeanMap = new HashMap<>();public ApplicationContext(String basePackage) throws UnsupportedEncodingException {scanPackage(basePackage);createBean();}/*** 1. 掃描包,掃描需要被創(chuàng)建的類,創(chuàng)建 Bean 定義對(duì)象,并放入 Bean 定義Map中*/public void scanPackage(String basePackage) throws UnsupportedEncodingException {// 獲取類加載器ClassLoader classLoader = this.getClass().getClassLoader();// 獲取包路徑String path = classLoader.getResource(basePackage.replace(".", "/")).getPath();// 路徑解碼,如果路徑有空格或者中文,會(huì)出現(xiàn) 16 進(jìn)制的字符String packagePath = URLDecoder.decode(path, "UTF-8");// 創(chuàng)建文件對(duì)象File fileDir = new File(packagePath);// 獲取包下的文件列表File[] files = fileDir.listFiles();for (File file : files) {if (file.isFile()) {// 判斷是否是class文件if (file.getName().endsWith(".class")) {// 包路徑 + 文件名 構(gòu)成全類名String className = basePackage + "." + file.getName().replace(".class", "");try {// 動(dòng)態(tài)加載了名為 className 的類,獲取該類的 Class 對(duì)象Class<?> aClass = Class.forName(className);// 判斷該類是否有 @Service 或 @Controller 注解if (aClass.isAnnotationPresent(Service.class) ||aClass.isAnnotationPresent(Controller.class)) {System.out.println("需要?jiǎng)?chuàng)建:" + className);// 將該類的類名首字母小寫(xiě)作為 idString id = aClass.getSimpleName().substring(0, 1).toLowerCase() + aClass.getSimpleName().substring(1);System.out.println("id:" + id);// 創(chuàng)建 Bean 定義對(duì)象,并放入 Bean 定義Map中beanDefinitionMap.put(id, new BeanDefinition(id, className));}} catch (ClassNotFoundException e) {e.printStackTrace();}}} else if (file.isDirectory()) {// 遞歸掃描子文件夾String subPackagePath = basePackage + "." + file.getName();scanPackage(subPackagePath);}}}/*** 2. 創(chuàng)建 Bean 實(shí)例,并放入 Bean Map 中*/public void createBean() {// 獲取 Bean 定義 Map 的 所有 idSet<String> ids = beanDefinitionMap.keySet();Iterator<String> it = ids.iterator();while (it.hasNext()) {String id = it.next();// 獲取 Bean 定義對(duì)象BeanDefinition beanDefinition = beanDefinitionMap.get(id);// 獲取 Bean 定義對(duì)象中的 Bean 的全類名String className = beanDefinition.getClassName();try {// 動(dòng)態(tài)加載類,并創(chuàng)建 Bean 實(shí)例,這時(shí)候的 Bean 是裸BeanObject bean = Class.forName(className).newInstance();// 將 Bean 實(shí)例放到 Bean Map 中BeanMap.put(id, bean);} catch (Exception e) {e.printStackTrace();}}System.out.println("實(shí)例化 Bean 完成");System.out.println(BeanMap);}
}
測(cè)試
4. 設(shè)置屬性
給Bean 對(duì)象做初始化,也就是依賴注入。Bean 的生命周期中屬于 Bean 的初始化
這里是使用類作為屬性進(jìn)行依賴注入,不是接口,后續(xù)需要優(yōu)化
1. 創(chuàng)建一個(gè)Controller
使用 @Autowired 注解,這里為了方便測(cè)試,重寫(xiě)一下 toString 方法
2. 屬性賦值
package com.shao.IOC;import com.shao.Annotation.Autowired;
import com.shao.Annotation.Controller;
import com.shao.Annotation.Service;import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;/*** ApplicationContext 類. 當(dāng)作 IOC 容器** @author shao.*/
public class ApplicationContext {/*** Bean 定義Map 存儲(chǔ)Bean 定義對(duì)象*/private HashMap<String, BeanDefinition> beanDefinitionMap = new HashMap<>();/*** Bean 實(shí)例Map 存儲(chǔ)Bean 實(shí)例對(duì)象*/private HashMap<String, Object> BeanMap = new HashMap<>();public ApplicationContext(String basePackage) throws UnsupportedEncodingException {scanPackage(basePackage);createBean();injectBean();}/*** 1. 掃描包,掃描需要被創(chuàng)建的類,創(chuàng)建 Bean 定義對(duì)象,并放入 Bean 定義Map中*/public void scanPackage(String basePackage) throws UnsupportedEncodingException {// 獲取類加載器ClassLoader classLoader = this.getClass().getClassLoader();// 獲取包路徑String path = classLoader.getResource(basePackage.replace(".", "/")).getPath();// 路徑解碼,如果路徑有空格或者中文,會(huì)出現(xiàn) 16 進(jìn)制的字符String packagePath = URLDecoder.decode(path, "UTF-8");// 創(chuàng)建文件對(duì)象File fileDir = new File(packagePath);// 獲取包下的文件列表File[] files = fileDir.listFiles();for (File file : files) {if (file.isFile()) {// 判斷是否是class文件if (file.getName().endsWith(".class")) {// 包路徑 + 文件名 構(gòu)成全類名String className = basePackage + "." + file.getName().replace(".class", "");try {// 動(dòng)態(tài)加載了名為 className 的類,獲取該類的 Class 對(duì)象Class<?> aClass = Class.forName(className);// 判斷該類是否有 @Service 或 @Controller 注解if (aClass.isAnnotationPresent(Service.class) ||aClass.isAnnotationPresent(Controller.class)) {System.out.println("需要?jiǎng)?chuàng)建:" + className);// 將該類的類名首字母小寫(xiě)作為 idString id = aClass.getSimpleName().substring(0, 1).toLowerCase() + aClass.getSimpleName().substring(1);System.out.println("id:" + id);// 創(chuàng)建 Bean 定義對(duì)象,并放入 Bean 定義Map中beanDefinitionMap.put(id, new BeanDefinition(id, className));}} catch (ClassNotFoundException e) {e.printStackTrace();}}} else if (file.isDirectory()) {// 遞歸掃描子文件夾String subPackagePath = basePackage + "." + file.getName();scanPackage(subPackagePath);}}}/*** 2. 創(chuàng)建 Bean 實(shí)例,并放入 Bean Map 中*/public void createBean() {// 獲取 Bean 定義 Map 的 所有 idSet<String> ids = beanDefinitionMap.keySet();Iterator<String> it = ids.iterator();while (it.hasNext()) {String id = it.next();// 獲取 Bean 定義對(duì)象BeanDefinition beanDefinition = beanDefinitionMap.get(id);// 獲取 Bean 定義對(duì)象中的 Bean 的全類名String className = beanDefinition.getClassName();try {// 動(dòng)態(tài)加載類,并創(chuàng)建 Bean 實(shí)例,這時(shí)候的 Bean 是裸BeanObject bean = Class.forName(className).newInstance();// 將 Bean 實(shí)例放到 Bean Map 中BeanMap.put(id, bean);} catch (Exception e) {e.printStackTrace();}}System.out.println("實(shí)例化 Bean 完成");System.out.println(BeanMap);}/*** 3. 給 Bean 設(shè)置屬性,Autowired 賦值*/public void injectBean() {// 獲取 Bean Map 的 所有 idIterator<String> it = BeanMap.keySet().iterator();while (it.hasNext()) {String id = it.next();// 獲取 Bean 實(shí)例Object bean = BeanMap.get(id);// 獲取 Bean 的 Class 對(duì)象Class<?> aClass = bean.getClass();// 獲取這個(gè)類的所有屬性,不包括父類的屬性Field[] declaredFields = aClass.getDeclaredFields();for (Field field : declaredFields) {// 判斷該屬性是否有 @Autowired 注解if (field.isAnnotationPresent(Autowired.class)) {// 設(shè)置屬性可訪問(wèn)field.setAccessible(true);try {// 給屬性賦值field.set(bean, BeanMap.get(field.getName()));} catch (IllegalAccessException e) {e.printStackTrace();}}}}System.out.println("屬性賦值完成");System.out.println(BeanMap);}
}
3. 測(cè)試
四、使用 Bean
1. 創(chuàng)建獲取 Bean 的方法
要使用 Bean ,需要從IOC 容器中獲取 Bean,所以還需要在 IOC 容器中提供獲取 Bean 的接口
package com.shao.IOC;import com.shao.Annotation.Autowired;
import com.shao.Annotation.Controller;
import com.shao.Annotation.Service;import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;/*** ApplicationContext 類. 當(dāng)作 IOC 容器** @author shao.*/
public class ApplicationContext {/*** Bean 定義Map 存儲(chǔ)Bean 定義對(duì)象*/private HashMap<String, BeanDefinition> beanDefinitionMap = new HashMap<>();/*** Bean 實(shí)例Map 存儲(chǔ)Bean 實(shí)例對(duì)象*/private HashMap<String, Object> BeanMap = new HashMap<>();public ApplicationContext(String basePackage) throws UnsupportedEncodingException {scanPackage(basePackage);createBean();injectBean();}/*** 1. 掃描包,掃描需要被創(chuàng)建的類,創(chuàng)建 Bean 定義對(duì)象,并放入 Bean 定義Map中*/public void scanPackage(String basePackage) throws UnsupportedEncodingException {// 獲取類加載器ClassLoader classLoader = this.getClass().getClassLoader();// 獲取包路徑String path = classLoader.getResource(basePackage.replace(".", "/")).getPath();// 路徑解碼,如果路徑有空格或者中文,會(huì)出現(xiàn) 16 進(jìn)制的字符String packagePath = URLDecoder.decode(path, "UTF-8");// 創(chuàng)建文件對(duì)象File fileDir = new File(packagePath);// 獲取包下的文件列表File[] files = fileDir.listFiles();for (File file : files) {if (file.isFile()) {// 判斷是否是class文件if (file.getName().endsWith(".class")) {// 包路徑 + 文件名 構(gòu)成全類名String className = basePackage + "." + file.getName().replace(".class", "");try {// 動(dòng)態(tài)加載了名為 className 的類,獲取該類的 Class 對(duì)象Class<?> aClass = Class.forName(className);// 判斷該類是否有 @Service 或 @Controller 注解if (aClass.isAnnotationPresent(Service.class) ||aClass.isAnnotationPresent(Controller.class)) {System.out.println("需要?jiǎng)?chuàng)建:" + className);// 將該類的類名首字母小寫(xiě)作為 idString id = aClass.getSimpleName().substring(0, 1).toLowerCase() + aClass.getSimpleName().substring(1);System.out.println("id:" + id);// 創(chuàng)建 Bean 定義對(duì)象,并放入 Bean 定義Map中beanDefinitionMap.put(id, new BeanDefinition(id, className));}} catch (ClassNotFoundException e) {e.printStackTrace();}}} else if (file.isDirectory()) {// 遞歸掃描子文件夾String subPackagePath = basePackage + "." + file.getName();scanPackage(subPackagePath);}}}/*** 2. 創(chuàng)建 Bean 實(shí)例,并放入 Bean Map 中*/public void createBean() {// 獲取 Bean 定義 Map 的 所有 idSet<String> ids = beanDefinitionMap.keySet();Iterator<String> it = ids.iterator();while (it.hasNext()) {String id = it.next();// 獲取 Bean 定義對(duì)象BeanDefinition beanDefinition = beanDefinitionMap.get(id);// 獲取 Bean 定義對(duì)象中的 Bean 的全類名String className = beanDefinition.getClassName();try {// 動(dòng)態(tài)加載類,并創(chuàng)建 Bean 實(shí)例,這時(shí)候的 Bean 是裸BeanObject bean = Class.forName(className).newInstance();// 將 Bean 實(shí)例放到 Bean Map 中BeanMap.put(id, bean);} catch (Exception e) {e.printStackTrace();}}System.out.println("實(shí)例化 Bean 完成");System.out.println(BeanMap);}/*** 3. 給 Bean 設(shè)置屬性,Autowired 賦值*/public void injectBean() {// 獲取 Bean Map 的 所有 idIterator<String> it = BeanMap.keySet().iterator();while (it.hasNext()) {String id = it.next();// 獲取 Bean 實(shí)例Object bean = BeanMap.get(id);// 獲取 Bean 的 Class 對(duì)象Class<?> aClass = bean.getClass();// 獲取這個(gè)類的所有屬性,不包括父類的屬性Field[] declaredFields = aClass.getDeclaredFields();for (Field field : declaredFields) {// 判斷該屬性是否有 @Autowired 注解if (field.isAnnotationPresent(Autowired.class)) {// 設(shè)置屬性可訪問(wèn)field.setAccessible(true);try {// 給屬性賦值field.set(bean, BeanMap.get(field.getName()));} catch (IllegalAccessException e) {e.printStackTrace();}}}}System.out.println("屬性賦值完成");System.out.println(BeanMap);}/*** 對(duì)外提供獲取 Bean 的接口*/public Object GetBean(String id) {return BeanMap.get(id);}public <T> T GetBean(Class<T> clazz) {// 獲取類名,首字母小寫(xiě)String id = clazz.getSimpleName().substring(0, 1).toLowerCase() + clazz.getSimpleName().substring(1);// 獲取 Bean 實(shí)例Object value = BeanMap.get(id);// 判斷 value 是否為 clazz 類型if (clazz.isInstance(value)) {// 安全的轉(zhuǎn)換類型return clazz.cast(value);} else {return null;}}
}
2. 使用 Bean?
這里為了方便測(cè)試,在Servlet 中獲取 Bean,然后調(diào)用 Bean 實(shí)例的方法
3. 測(cè)試
五、優(yōu)化 IOC 容器
現(xiàn)在需要注入依賴的屬性是類,不是接口,需要改成給接口賦值其 實(shí)現(xiàn)類的對(duì)象