成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

從零開始實現(xiàn)一個簡易的Java MVC框架(二)--實現(xiàn)Bean容器

paulquei / 3144人閱讀

摘要:容器實際上就是存放所有的地方,即以及相關(guān)信息對應(yīng)其實體的容器,為什么稱之為呢,因為在中,定義信息和實例的東西叫。了解到這個以后接下來就可以開始編寫容器了,在包下創(chuàng)建一個類叫。獲取容器實例至此,這個容器就完成了。

項目準(zhǔn)備

首先確保你擁有以下環(huán)境或者工具

idea

java 8

maven 3.3.X

lombok插件

然后我們創(chuàng)建一個maven工程,編寫pom.xml引入一些需要的依賴


    1.8
    1.8
    UTF-8
    1.7.25
    1.16.20


    
    
        org.slf4j
        slf4j-log4j12
        ${slf4j-api.version}
    
    
    
        org.projectlombok
        lombok
        ${lombok.version}
        provided
    

目前只需要lombok和log4j兩個依賴就可以完成前面幾個功能的實現(xiàn),其他需要的依賴等到后面需要的時候再加。

接著把項目一些基本的包結(jié)構(gòu)創(chuàng)建一下,如下圖

resources文件夾下的log4j.properties文件為log4j輸出格式化參數(shù),大家可以根據(jù)自己的喜好和需求編寫,我自己的只是為了方便調(diào)試使用的,下面是我自己的。

### 設(shè)置###
log4j.rootLogger = debug,stdout
### 輸出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %c %d{ISO8601} -- %p -- %m%n
創(chuàng)建工具類

為了方便后續(xù)代碼的編寫,我們先創(chuàng)建工具類。

com.zbw.util包下創(chuàng)建兩個工具類:ValidateUtilClassUtil

ValidateUtil主要負責(zé)屬性的驗證,這個類的完整代碼就不貼了,就是檢查各種類型的值是否為空或者是否不為空。

/**
 * 驗證相關(guān)工具類
 */
public final class ValidateUtil {

    /**
     * Object是否為null
     */
    public static boolean isEmpty(Object obj) {
        return obj == null;
    }

    /**
     * String是否為null或""
     */
    public static boolean isEmpty(String obj) {
        return (obj == null || "".equals(obj));
    }
    
    ...

    /**
     * Object是否不為null
     */
    public static boolean isNotEmpty(Object obj) {
        return !isEmpty(obj);
    }

    /**
     * String是否不為null或""
     */
    public static boolean isNotEmpty(String obj) {
        return !isEmpty(obj);
    }

    ...
}

ClassUtil主要是Class的一些相關(guān)操作。這其中除了一些類常用的實例反射等操作,還有一個重要方法就是getPackageClass(),這個方法會遞歸遍歷傳入的包名下的所有類文件,并返回一個Set>。等一下在實現(xiàn)Bean容器的時候就會使用這個方法來掃描獲取對應(yīng)包下的所有類文件。

/**
 * 類操作工具類
 */
@Slf4j
public final class ClassUtil {

    /**
     * file形式url協(xié)議
     */
    public static final String FILE_PROTOCOL = "file";

    /**
     * jar形式url協(xié)議
     */
    public static final String JAR_PROTOCOL = "jar";

    /**
     * 獲取classLoader
     */
    public static ClassLoader getClassLoader() {
        return Thread.currentThread().getContextClassLoader();
    }

    /**
     * 獲取Class
     */
    public static Class loadClass(String className) {
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            log.error("load class error", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 實例化class
     */
    @SuppressWarnings("unchecked")
    public static  T newInstance(String className) {
        try {
            Class clazz = loadClass(className);
            return (T) clazz.newInstance();
        } catch (Exception e) {
            log.error("newInstance error", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 實例化class
     */
    @SuppressWarnings("unchecked")
    public static  T newInstance(Class clazz) {
        try {
            return (T) clazz.newInstance();
        } catch (Exception e) {
            log.error("newInstance error", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 設(shè)置類的屬性值
     */
    public static void setField(Field field, Object target, Object value) {
        setField(field, target, value, true);
    }

    /**
     * 設(shè)置類的屬性值
     */
    public static void setField(Field field, Object target, Object value, boolean accessible) {
        field.setAccessible(accessible);
        try {
            field.set(target, value);
        } catch (IllegalAccessException e) {
            log.error("setField error", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 獲取包下類集合
     */
    public static Set> getPackageClass(String basePackage) {
        URL url = getClassLoader()
                .getResource(basePackage.replace(".", "/"));
        if (null == url) {
            throw new RuntimeException("無法獲取項目路徑文件");
        }
        try {
            if (url.getProtocol().equalsIgnoreCase(FILE_PROTOCOL)) {
                // 若為普通文件夾,則遍歷
                File file = new File(url.getFile());
                Path basePath = file.toPath();
                return Files.walk(basePath)
                        .filter(path -> path.toFile().getName().endsWith(".class"))
                        .map(path -> getClassByPath(path, basePath, basePackage))
                        .collect(Collectors.toSet());
            } else if (url.getProtocol().equalsIgnoreCase(JAR_PROTOCOL)) {
                // 若在 jar 包中,則解析 jar 包中的 entry
                JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
                return jarURLConnection.getJarFile()
                        .stream()
                        .filter(jarEntry -> jarEntry.getName().endsWith(".class"))
                        .map(ClassUtil::getClassByJar)
                        .collect(Collectors.toSet());
            }
            return Collections.emptySet();
        } catch (IOException e) {
            log.error("load package error", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 從Path獲取Class
     */
    private static Class getClassByPath(Path classPath, Path basePath, String basePackage) {
        String packageName = classPath.toString().replace(basePath.toString(), "");
        String className = (basePackage + packageName)
                .replace("/", ".")
                .replace("", ".")
                .replace(".class", "");
        return loadClass(className);
    }

    /**
     * 從jar包獲取Class
     */
    private static Class getClassByJar(JarEntry jarEntry) {
        String jarEntryName = jarEntry.getName();
        // 獲取類名
        String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
        return loadClass(className);
    }
}
實現(xiàn)Bean容器

現(xiàn)在開始可以實現(xiàn)Bean容器了。

基礎(chǔ)注解

在spring中我們總是用各種注解去標(biāo)注我們的組件,如controller等。所以我們也要先寫一些注解來標(biāo)注一些必要的組件。在zbw.core包下再創(chuàng)建一個annotation包,然后再創(chuàng)建四個最基本的組件.

// Component注解,用于標(biāo)記組件
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
}
// Controller注解,用于標(biāo)記Controller層的組件
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
}
// Repository注解,用于標(biāo)記Dao層的組件
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Repository {
}
// Service注解,用于標(biāo)記Service層的組件
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {
}

這四個注解都是只能標(biāo)注在類上的,他們實際上沒有任何作用,只是用來標(biāo)記這個類的,我們在后面的類集合中就可以很方便的獲取和區(qū)分被這些注解標(biāo)記的類。

BeanContainer

Bean容器實際上就是存放所有Bean的地方,即Class以及相關(guān)信息對應(yīng)其實體的容器,為什么稱之為"Bean"呢,因為在spring中,定義Class信息和實例的東西叫BeanDefinition。這是一個接口,他有一個模板類AbstractBeanDefinition,這里面就有一個beanClass變量存放Class類和propertyValues變量存放類屬性,以及很多類相關(guān)參數(shù)和初始化之類的參數(shù)。大家可以去spring中看看,spring的所有都是依賴于這個Bean生成的,可以說這是spring的基石。

了解到這個以后接下來就可以開始編寫B(tài)ean容器了,在zbw.core包下創(chuàng)建一個類叫BeanContainer。

/**
 * Bean容器
 */
@Slf4j
public class BeanContainer {
    /**
     * 存放所有Bean的Map
     */
    private final Map, Object> beanMap = new ConcurrentHashMap<>();

    /**
     * 獲取Bean實例
     */
    public Object getBean(Class clz) {
        if (null == clz) {
            return null;
        }
        return beanMap.get(clz);
    }

    /**
     * 獲取所有Bean集合
     */
    public Set getBeans() {
        return new HashSet<>(beanMap.values());
    }

    /**
     * 添加一個Bean實例
     */
    public Object addBean(Class clz, Object bean) {
        return beanMap.put(clz, bean);
    }

    /**
     * 移除一個Bean實例
     */
    public void removeBean(Class clz) {
        beanMap.remove(clz);
    }

    /**
     * Bean實例數(shù)量
     */
    public int size() {
        return beanMap.size();
    }

    /**
     * 所有Bean的Class集合
     */
    public Set> getClasses() {
        return beanMap.keySet();
    }

    /**
     * 通過注解獲取Bean的Class集合
     */
    public Set> getClassesByAnnotation(Class annotation) {
        return beanMap.keySet()
                .stream()
                .filter(clz -> clz.isAnnotationPresent(annotation))
                .collect(Collectors.toSet());
    }

    /**
     * 通過實現(xiàn)類或者父類獲取Bean的Class集合
     */
    public Set> getClassesBySuper(Class superClass) {
        return beanMap.keySet()
                .stream()
                .filter(superClass::isAssignableFrom)
                .filter(clz -> !clz.equals(superClass))
                .collect(Collectors.toSet());
    }
}

我們不需要像spring那樣存放很多的信息,所以用一個Map來存儲Bean的信息就好了。Map的Key為Class類,Value為這個Class的實例Object。配合getBean(),addBean()等方法就可以很方便的操作Class和它的實例。

然而現(xiàn)在這個Map里還沒有存放任何的Bean數(shù)據(jù),所以編寫一個loadBeans()方法來初始化加載Bean。

首先在BeanContainer中添加一個變量isLoadBean和一個常量BEAN_ANNOTATION

//BeanContainer
...

/**
* 是否加載Bean
*/
private boolean isLoadBean = false;

/**
* 加載bean的注解列表
*/
private static final List> BEAN_ANNOTATION 
= Arrays.asList(Component.class, Controller.class, Service.class, Repository.class);

...

然后編寫loadBeans()方法去加載被BEAN_ANNOTATION中的注解類注解的類,以及對應(yīng)的實例。通過剛才的ClassUtil.getPackageClass(basePackage)獲取我們項目下所有的Class,然后判斷該Class是否被BEAN_ANNOTATION中注解類注解,如果有就說明該Class是一個Bean,對其實例化并且放入Map中。

//BeanContainer
...


/**
* 掃描加載所有Bean
*/
public void loadBeans(String basePackage) {
    if (isLoadBean()) {
        log.warn("bean已經(jīng)加載");
        return;
    }

    Set> classSet = ClassUtil.getPackageClass(basePackage);
    classSet.stream()
        .filter(clz -> {
            for (Class annotation : BEAN_ANNOTATION) {
                if (clz.isAnnotationPresent(annotation)) {
                    return true;
                }
            }
            return false;
        })
        .forEach(clz -> beanMap.put(clz, ClassUtil.newInstance(clz)));
    isLoadBean = true;
}

/**
* 是否加載Bean
*/
public boolean isLoadBean() {
    return isLoadBean;
}
...

最后,為了能夠保證整個項目全局Bean的唯一性,我們要保證這個BeanContainer是唯一的,將該類單例化。

通過lombok的注解@NoArgsConstructor(access = AccessLevel.PRIVATE)生成私有構(gòu)造函數(shù),再用內(nèi)部枚舉生成唯一的BeanContainer實例。

@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BeanContainer {
    /**
     * 獲取Bean容器實例
     */
    public static BeanContainer getInstance() {
        return ContainerHolder.HOLDER.instance;
    }
    
    ...
    
   private enum ContainerHolder {
        HOLDER;
        private BeanContainer instance;

        ContainerHolder() {
            instance = new BeanContainer();
        }
    }
}

至此,這個Bean容器就完成了。我們可以通過loadBeans()方法初始化Bean,然后可以通過getBean(),addBean(),removeBean()等方法去操作這個Bean,為后面的IOC,AOP等功能打下基礎(chǔ)。

從零開始實現(xiàn)一個簡易的Java MVC框架(一)--前言

從零開始實現(xiàn)一個簡易的Java MVC框架(二)--實現(xiàn)Bean容器

從零開始實現(xiàn)一個簡易的Java MVC框架(三)--實現(xiàn)IOC

從零開始實現(xiàn)一個簡易的Java MVC框架(四)--實現(xiàn)AOP

從零開始實現(xiàn)一個簡易的Java MVC框架(五)--引入aspectj實現(xiàn)AOP切點

從零開始實現(xiàn)一個簡易的Java MVC框架(六)--加強AOP功能

從零開始實現(xiàn)一個簡易的Java MVC框架(七)--實現(xiàn)MVC

從零開始實現(xiàn)一個簡易的Java MVC框架(八)--制作Starter

從零開始實現(xiàn)一個簡易的Java MVC框架(九)--優(yōu)化MVC代碼

源碼地址:doodle

原文地址:從零開始實現(xiàn)一個簡易的Java MVC框架--實現(xiàn)Bean容器

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/71459.html

相關(guān)文章

  • 從零開始實現(xiàn)一個簡易Java MVC框架

    摘要:不過仔細了解了一段時候發(fā)現(xiàn),其實他的原理是很簡單的,所以想要自己也動手實現(xiàn)一個功能類似的框架。原文地址從零開始實現(xiàn)一個簡易的框架 前言 最近在看spring-boot框架的源碼,看了源碼之后更是讓我感受到了spring-boot功能的強大。而且使用了很多的設(shè)計模式,讓人在看的時候覺得有點難以下手。 不過仔細了解了一段時候發(fā)現(xiàn),其實他的原理是很簡單的,所以想要自己也動手實現(xiàn)一個功能類似的...

    neuSnail 評論0 收藏0
  • 從零開始實現(xiàn)一個簡易Java MVC框架(五)--引入aspectj實現(xiàn)AOP切點

    摘要:接下來就可以把這個切點類加入到我們之前實現(xiàn)的功能中了。實現(xiàn)的切點功能首先改裝注解,把之前改成來存儲表達式。測試用例在上一篇文章從零開始實現(xiàn)一個簡易的框架四實現(xiàn)中的測試用例的基礎(chǔ)上修改測試用例。 前言 在上一節(jié)從零開始實現(xiàn)一個簡易的Java MVC框架(四)--實現(xiàn)AOP中我們實現(xiàn)了AOP的功能,已經(jīng)可以生成對應(yīng)的代理類了,但是對于代理對象的選擇只能通過指定的類,這樣確實不方便也不合理。...

    wupengyu 評論0 收藏0
  • 從零開始實現(xiàn)一個簡易Java MVC框架(八)--制作Starter

    摘要:服務(wù)器相關(guān)配置啟動類資源目錄目錄靜態(tài)文件目錄端口號目錄目錄實現(xiàn)內(nèi)嵌服務(wù)器在上一章文章從零開始實現(xiàn)一個簡易的框架七實現(xiàn)已經(jīng)在文件中引入了依賴,所以這里就不用引用了。 spring-boot的Starter 一個項目總是要有一個啟動的地方,當(dāng)項目部署在tomcat中的時候,經(jīng)常就會用tomcat的startup.sh(startup.bat)的啟動腳本來啟動web項目 而在spring-b...

    AprilJ 評論0 收藏0
  • 從零開始實現(xiàn)一個簡易Java MVC框架(六)--加強AOP功能

    摘要:在前面的文章中實現(xiàn)的功能時,目標(biāo)類都只能被一個切面代理,如果想要生成第二個代理類,就會把之前的代理類覆蓋。改裝原有功能現(xiàn)在要改裝原來的的實現(xiàn)代碼,讓的功能加入到框架中為了讓切面能夠排序,先添加一個注解,用于標(biāo)記排序。 前言 在前面從零開始實現(xiàn)一個簡易的Java MVC框架(四)--實現(xiàn)AOP和從零開始實現(xiàn)一個簡易的Java MVC框架(五)--引入aspectj實現(xiàn)AOP切點這兩節(jié)文章...

    Loong_T 評論0 收藏0
  • 從零開始實現(xiàn)一個簡易Java MVC框架(九)--優(yōu)化MVC代碼

    摘要:前言在從零開始實現(xiàn)一個簡易的框架七實現(xiàn)中實現(xiàn)了框架的的功能,不過最后指出代碼的邏輯不是很好,在這一章節(jié)就將這一部分代碼進行優(yōu)化。 前言 在從零開始實現(xiàn)一個簡易的Java MVC框架(七)--實現(xiàn)MVC中實現(xiàn)了doodle框架的MVC的功能,不過最后指出代碼的邏輯不是很好,在這一章節(jié)就將這一部分代碼進行優(yōu)化。 優(yōu)化的目標(biāo)是1.去除DispatcherServlet請求分發(fā)器中的http邏...

    ruicbAndroid 評論0 收藏0

發(fā)表評論

0條評論

paulquei

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<