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