springioc注解版运行效果演示
生活随笔
收集整理的這篇文章主要介紹了
springioc注解版运行效果演示
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
我們講一個新的知識,就是手寫一下IOC容器,怎么手寫一下SpringIOC XML版本,還有手寫一下SpringIOC注解的版本,那么相對來說,我們用注解版本的次數(shù)可能要多點(diǎn),很少用到XML版本,XML版本會比較麻煩,那我今天會把兩種IOC方式的全部講一下,那么大家可以看一下,我已經(jīng)準(zhǔn)備好了一個Demo了,我自己去寫的一個案例,自己去自定義一個注解,然后實(shí)現(xiàn)一下,還是一個類似于service注解的功能,首先只要在類上加上ExtService注解,他就會把UserService這樣的一個類注入到Spring容器里面去,我只要加上@ExtService注解,他就會直接去Spring容器中去獲取這樣的一個bean,直接復(fù)制給他,你們再點(diǎn)進(jìn)去看一下,然后我們找到OrderService,是不是也是用到我自己定義的注解,那么我們今天實(shí)現(xiàn)什么效果呢,就是他底層是怎么實(shí)現(xiàn)起來的,你們之前可能用過@Service這種方式,我不知道你們有沒有了解過他的原理是什么,他是怎么可以注入到這個bean的,他怎么知道我加上注解之后,就可以把這個對象注入到Spring容器中里面去呢,有沒有人知道是為什么的,有沒有誰之前了解過的,我怎么知道只要上面加上@Service注解,就會把這個對象注入到Spring容器里面去,掃包反射機(jī)制,我們看看效果,看效果你們就明白案例了
package com.learn.spring;import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;import org.apache.commons.lang.StringUtils;import com.learn.annotation.ExtService;
import com.learn.utils.ClassUtil;/*** 這個classPath是我自己寫的* 完全是我自己寫的* 這是我們通過注解方式實(shí)現(xiàn)* 源碼它是用了很多設(shè)計(jì)模式* 抽取出來了* * * @author Leon.Sun**/
@SuppressWarnings({ "rawtypes", "unchecked" })
public class ClassPathXmlApplicationContext {// 掃包范圍private String packageName;/*** ConcurrentHashMap的集合* 專門用來裝bean的* * */ConcurrentHashMap<String, Object> initBean = null;public ClassPathXmlApplicationContext(String packageName) {this.packageName = packageName;}// 使用beanID查找對象public Object getBean(String beanId) throws Exception {// 1.使用反射機(jī)制獲取該包下所有的類已經(jīng)存在bean的注解類List<Class> listClassesAnnotation = findClassExisService();if (listClassesAnnotation == null || listClassesAnnotation.isEmpty()) {throw new Exception("沒有需要初始化的bean");}// 2.使用Java反射機(jī)制初始化對象initBean = initBean(listClassesAnnotation);if (initBean == null || initBean.isEmpty()) {throw new Exception("初始化bean為空!");}// 3.使用beanID查找查找對應(yīng)bean對象Object object = initBean.get(beanId);// 4.使用反射讀取類的屬性,賦值信息attriAssign(object);return object;}// 使用反射讀取類的屬性,賦值信息public void attriAssign(Object object) throws IllegalArgumentException, IllegalAccessException {// 1.獲取類的屬性是否存在 獲取bean注解Class<? extends Object> classInfo = object.getClass();Field[] declaredFields = classInfo.getDeclaredFields();for (Field field : declaredFields) {// 屬性名稱String name = field.getName();// 2.使用屬性名稱查找bean容器賦值Object bean = initBean.get(name);if (bean != null) {// 私有訪問允許訪問field.setAccessible(true);// 給屬性賦值field.set(object, bean);continue;}}}// 使用反射機(jī)制獲取該包下所有的類已經(jīng)存在bean的注解類public List<Class> findClassExisService() throws Exception {// 1.使用反射機(jī)制獲取該包下所有的類if (StringUtils.isEmpty(packageName)) {throw new Exception("掃包地址不能為空!");}// 2.使用反射技術(shù)獲取當(dāng)前包下所有的類List<Class<?>> classesByPackageName = ClassUtil.getClasses(packageName);// 3.存放類上有bean注入注解List<Class> exisClassesAnnotation = new ArrayList<Class>();// 4.判斷該類上屬否存在注解for (Class classInfo : classesByPackageName) {ExtService extService = (ExtService) classInfo.getDeclaredAnnotation(ExtService.class);if (extService != null) {exisClassesAnnotation.add(classInfo);continue;}}return exisClassesAnnotation;}// 初始化bean對象public ConcurrentHashMap<String, Object> initBean(List<Class> listClassesAnnotation)throws InstantiationException, IllegalAccessException {ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap<String, Object>();for (Class classInfo : listClassesAnnotation) {// 初始化對象Object newInstance = classInfo.newInstance();// 獲取父類名稱String beanId = toLowerCaseFirstOne(classInfo.getSimpleName());concurrentHashMap.put(beanId, newInstance);}return concurrentHashMap;}// 首字母轉(zhuǎn)小寫public static String toLowerCaseFirstOne(String s) {if (Character.isLowerCase(s.charAt(0)))return s;elsereturn (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();}}
package com.learn.service;public interface UserService {public void add();}
package com.learn.service.impl;import com.learn.annotation.ExtResource;
import com.learn.annotation.ExtService;
import com.learn.service.OrderService;
import com.learn.service.UserService;//將該類注入到spring容器里面
/*** 就是UserServiceImpl這樣一個bean* 我們現(xiàn)在使用的都是自定義注解* 只要是加上我們這個自定義注解之后* 那么這個時候他就會去注入bean的* 就會自動去獲取bean* * * @author Leon.Sun**/
@ExtService
public class UserServiceImpl implements UserService {// 從Spring容器中讀取bean/*** 為什我加上@ExtResource這么一個注解* 就可以獲取orderServiceImpl這么一個對象* 是不是這樣的* 這就是我要講的原理的過程* 我把這個@ExtService注解給注掉* @ExtResource* private OrderService orderServiceImpl;* 這里還能取到嗎* 還能不能取到* 能不能取到這個對象* 能不能取到OrderService* 肯定取不到* 為什么呢* 我們運(yùn)行一遍* java.lang.NullPointerException* 是不是報(bào)了一個空指針* 我把@ExtService注解一加上去* 一加上去就可以運(yùn)行了* 看到效果沒有* 我來講一下整個實(shí)現(xiàn)原理* 我今天還來講一個知識* 什么知識呢* XML版本的* xml版本的可能稍微簡單點(diǎn)* * * */@ExtResourceprivate OrderService orderServiceImpl;public void add() {/*** 這里會調(diào)用addOrder()* 是不是這樣的* * */orderServiceImpl.addOrder();System.out.println("我是使用反射機(jī)制運(yùn)行的方法");}}
package com.learn.service;public interface OrderService {public void addOrder();}
package com.learn.service.impl;import com.learn.annotation.ExtService;
import com.learn.service.OrderService;/*** 這里也是加上了@ExtService注解* 這就是我要講的整個原理* 原計(jì)劃是要講源碼分析* 但是我覺得源碼分析比較抽象* 看起來很難學(xué)得到* 我花了兩個小時去手寫了一下* 就是跟著我自己的思路去把他寫出來* 然后講一下他怎么實(shí)現(xiàn)的原理* 這是我要給大家說的最多的一句話* 代碼怎么寫都不重要* 就是你整個過程的思想* 就學(xué)他整個原理* 為什么能在整個類上加上這個注解* 他怎么自動的注入到Spring容器里面去* 為什么我加上這么一個注解* 然后我們看一個效果* * * @author Leon.Sun**/
@ExtService
public class OrderServiceImpl implements OrderService {@Overridepublic void addOrder() {System.out.println("addOrder");}}
package com.learn;import com.learn.service.UserService;
import com.learn.spring.ClassPathXmlApplicationContext;public class Test001 {public static void main(String[] args) throws Exception {ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("com.learn.service.impl");/*** 傳入我要獲取的bean* */UserService userService = (UserService) app.getBean("userServiceImpl");userService.add();}}
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd"><!-- 我們只要在我們的配置文件里面 先注入一個bean的id,class寫入一個完整路徑地址--><bean id="user" class="com.learn.entity.User"></bean><!-- aop的掃包注解是有的 --><context:component-scan base-package="com.learn"></context:component-scan>
</beans>
package com.learn.entity;public class User {}
?
總結(jié)
以上是生活随笔為你收集整理的springioc注解版运行效果演示的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring七中传播行为详解
- 下一篇: springiocxml方式注入对象原理