springIOC ann版本
如果覺得還可以 記得關注一下公衆號哦!一起交流學習!
如約而至,瞭解上個版本的XML配置IOC後,你是否對註解版本的更感興趣了呢?一起學習下Spring的註解版本的吧!
pom.xml
<dependencies>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
一、自定義註解
自定義註解
1.Autowired註解
package com.luban.annotatethebook.anno;
import java.lang.annotation.*;
/**
* 自動注入
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}
2.ComponentScan註解
package com.luban.annotatethebook.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
public String value();
}
3.Repository註解
package com.luban.annotatethebook.anno;
import jdk.nashorn.internal.objects.annotations.Property;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 標註DAO
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Repository {
public String value() default "";
}
4.Service註解
package com.luban.annotatethebook.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 標註Service
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Service {
public String value() default "";
}
二、註解異常
1.沒有配置類異常實現
package com.luban.exception;
/**
* 找不到配置註解異常類
* @author 皇甫
*/
public class CannotFindAnnotationsException extends RuntimeException {
public CannotFindAnnotationsException(String msg) {
super(msg);
}
}
2.依賴查找異常
package com.luban.exception;
public class LubanSpringException extends RuntimeException {
public LubanSpringException(String msg){
super(msg);
}
}
3.重複標註beanNane異常實現
package com.luban.exception;
/**
* @author 皇甫
*/
public class RepeatAnnotationException extends RuntimeException {
public RepeatAnnotationException(String msg){
super(msg);
}
}
三、創建器(核心)
package com.luban.util;
import com.luban.annotatethebook.anno.Autowired;
import com.luban.annotatethebook.anno.ComponentScan;
import com.luban.annotatethebook.anno.Repository;
import com.luban.annotatethebook.anno.Service;
import com.luban.exception.CannotFindAnnotationsException;
import com.luban.exception.LubanSpringException;
import com.luban.exception.RepeatAnnotationException;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 自定義版本的註解掃描
* @author 皇甫
*/
public class AnnotationConfigApplicationContext {
/**
* 有依賴的Map
*/
Map<String,Object> relyMap = new HashMap<String, Object>();
/**
* 沒有依賴的Map
*/
Map<String,Object> noDependenceMap = new HashMap<String, Object>();
/**
* 將實例好的對象全部放入Map集合
*/
Map<String,Object> map = new HashMap<String, Object>();
private String fullyQualifiedName;
public AnnotationConfigApplicationContext(Class target) {
try {
getTYpePath(target);
} catch (Exception e) {
e.printStackTrace();
}
}
private void getTYpePath(Class target) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
if(target.isAnnotationPresent(ComponentScan.class)){
ComponentScan componentScanValue = (ComponentScan) target.getAnnotation(ComponentScan.class);
String packagePath = componentScanValue.value();
fullyQualifiedName = packagePath;
//將包名轉換爲路徑名稱
String path = packagePath.replaceAll("\\.","/" );
//獲取當前項目根路徑
String rootPackagePath = this.getClass().getResource("/").getPath();
//類的全路徑名
String targetPackagePath = rootPackagePath+path;
File file = new File(targetPackagePath);
//所有class文件的全路徑名稱
List<String> list = new ArrayList<String>();
list = getPaths(file, list);
//所有class文件的全限定名
List<String> fullyQualifiedNames = getFullyQualifiedName(list);
//所有class文件對應的class對象
List<Class> classArray = getClassArray(fullyQualifiedNames);
//返回所有添加註解的類對象
List<Class> yesAnnotation = scanningAnnotations(classArray);
//剩餘的除了沒有依賴的bean類對象 Service
List<Class> yesRelyArray = getNoDependenceMap(yesAnnotation);
//實例化有依賴的對象
getRelyMap(yesRelyArray);
//合併
mergeMap();
}else{
throw new CannotFindAnnotationsException("找不到"+ComponentScan.class+"註解");
}
}
/**
* 合併兩個Map
*/
private void mergeMap(){
for (String noDependenceMapKey : noDependenceMap.keySet()) {
map.put(noDependenceMapKey, noDependenceMap.get(noDependenceMapKey));
}
for (String relyMapKey : relyMap.keySet()) {
map.put(relyMapKey, relyMap.get(relyMapKey));
}
}
/**
* 實例化有依賴的對象
* @param yesRelyArray
* @throws IllegalAccessException
* @throws InstantiationException
*/
private void getRelyMap(List<Class> yesRelyArray) throws IllegalAccessException, InstantiationException {
String relyMapKey = null;
for (Class clazz : yesRelyArray) {
//判斷註解裏面是否有名字例:@Service(userService)
Repository repository = (Repository) clazz.getAnnotation(Repository.class);
Service service = (Service) clazz.getAnnotation(Service.class);
String repositoryValue = "";
String serviceValue = "";
if(repository!=null){
repositoryValue = repository.value();
}
if(service!=null){
serviceValue = service.value();
}
if(repositoryValue != ""){
relyMapKey = repositoryValue;
}else if(serviceValue!=""){
relyMapKey = serviceValue;
}else{
throw new RepeatAnnotationException("存在重複註解");
}
Field[] declaredFields = clazz.getDeclaredFields();
if(declaredFields.length>0){
int i = 0;
Object o = null;
for (Field declaredField : declaredFields) {
//沒有加註解的直接跳過
if(!declaredField.isAnnotationPresent(Autowired.class)){
continue;
}
String fieldTypeName = declaredField.getType().getName();
//循環沒有依賴的Map
for (String key : noDependenceMap.keySet()) {
String typeName = noDependenceMap.get(key).getClass().getInterfaces()[0].getName();
if(fieldTypeName!=null && fieldTypeName.equals(typeName)){
i++;
o = noDependenceMap.get(key);
}
}
if(i>1){
throw new LubanSpringException("需要一個"+fieldTypeName+"類型的依賴,卻找到"+i+"個");
}else{
//註解值爲空時默認使用類名
if(relyMapKey==null || relyMapKey.equals("")){
relyMapKey = clazz.getSimpleName();
relyMapKey = lowerFirst(relyMapKey);
}
Object object = clazz.newInstance();
declaredField.setAccessible(true);
declaredField.set(object,o);
relyMap.put(relyMapKey, object);
}
}
}
}
}
/**
* 首字母小寫
* @param oldStr
* @return
*/
private String lowerFirst(String oldStr){
char[]chars = oldStr.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
/**
* 返回添加註解的Dao或者Service
* @param classArray
* @return
*/
private List<Class> scanningAnnotations(List<Class> classArray){
List<Class> daoAndServiceClazz = new ArrayList<Class>();
for (Class clazz : classArray) {
if(clazz.isAnnotationPresent(Repository.class) || clazz.isAnnotationPresent(Service.class)){
daoAndServiceClazz.add(clazz);
}
}
return daoAndServiceClazz;
}
/**
* 查找沒有依賴的對象 並實例化
* @param yesAnnotation
*/
private List<Class> getNoDependenceMap(List<Class> yesAnnotation){
String noDependenceMapKey = null;
for (Class aClass : yesAnnotation) {
Repository repository = (Repository) aClass.getAnnotation(Repository.class);
Service service = (Service) aClass.getAnnotation(Service.class);
String repositoryValue = "";
String serviceValue = "";
//判斷註解裏面是否有名字例:@Repository(userDao)
if(repository!=null){
repositoryValue = repository.value();
}
if(service!=null){
serviceValue = service.value();
}
if(repositoryValue != ""){
noDependenceMapKey = repositoryValue;
}else if(serviceValue!=""){
noDependenceMapKey = serviceValue;
}else{
throw new RepeatAnnotationException("存在重複註解");
}
boolean isNoRely = true;
Field[] declaredFields = aClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
if(declaredField.isAnnotationPresent(Autowired.class)){
isNoRely = false;
}
}
if(isNoRely){
//此時的映射關係爲 {UserDaoImpl=com.luban.annotatethebook.dao.impl.UserDaoImpl@49476842}
//疑問 如果不同包的Dao都叫UserDaoImpl 根據map key不能重複的理論,有一個Dao將會註冊失敗
try {
Object target = aClass.newInstance();
//註解值爲空時默認使用類名
if(noDependenceMapKey==null || noDependenceMapKey.equals("")){
noDependenceMapKey = aClass.getSimpleName();
noDependenceMapKey = lowerFirst(noDependenceMapKey);
}
noDependenceMap.put(noDependenceMapKey, target);
yesAnnotation.remove(aClass);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return yesAnnotation;
}
/**
* 遞歸查詢所有文件的全路徑名
* @param filePath
* @param paths
* @return
*/
private List<String> getPaths(File filePath,List<String> paths){
File[] files = filePath.listFiles();
if(files.length == 0){
return null;
}
for (File file : files) {
if(file.isDirectory()){
getPaths(file,paths);
}else{
paths.add(file.getPath());
}
}
return paths;
}
/**
* 根據全路徑名稱返回全限定名
* @param list
* @return
*/
private List<String> getFullyQualifiedName(List<String> list){
List<String> fullyQualifiedNames = new ArrayList<String>();
for (String name : list) {
String s = name.replaceAll("\\\\", "\\.");
String substring = s.substring(s.indexOf(fullyQualifiedName), (s.length() - 6));
fullyQualifiedNames.add(substring);
}
return fullyQualifiedNames;
}
/**
* 根據全限定名 返回對應的class對象
* @param list
* @return
*/
private List<Class> getClassArray(List<String> list){
List<Class> classes = new ArrayList<Class>();
for (String fullyQualifiedName : list) {
try {
Class clazz = Class.forName(fullyQualifiedName);
classes.add(clazz);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return classes;
}
public Object getBean(String name){
return map.get(name);
}
}
四、測試
1.配置類
package com.luban.annotatethebook.conf;
import com.luban.annotatethebook.anno.ComponentScan;
/**
* @author 皇甫
*/
@ComponentScan("com.luban.annotatethebook")
public class AppConfig {
}
2.service註解(不寫完了,舉個例子)
package com.luban.annotatethebook.service;
/**
* 用戶業務類
* @author 皇甫
*/
public interface UserService {
/**
* 查詢方法
* @return
*/
public String findUser();
}
3.測試
package com.luban.annotatethebook.test;
import com.luban.annotatethebook.conf.AppConfig;
import com.luban.annotatethebook.service.UserService;
import com.luban.util.AnnotationConfigApplicationContext;
/**
* @author 皇甫
*/
public class ConfigTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext =
new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService= (UserService) annotationConfigApplicationContext.getBean("userService");
String user = userService.findUser();
System.out.println(user);
}
}