欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Java中自定義注解的使用

 更新時間:2023年03月20日 11:47:47   作者:劉架構(gòu)  
Annontation是Java5開始引入的新特征,中文名稱叫注解,它提供了一種安全的類似注釋的機(jī)制,用來將任何的信息或元數(shù)據(jù)(metadata)與程序元素(類、方法、成員變量等)進(jìn)行關(guān)聯(lián)。本文主要介紹了自定義注解的使用,希望對大家有所幫助

什么是注解

在早期的工作的時候 ,自定義注解寫的比較多,可大多都只是因為 這樣看起來 不會存在一堆代碼耦合在一起的情況,所以使用了自定義注解,這樣看起來清晰些,

Annontation是Java5開始引入的新特征,中文名稱叫注解。

它提供了一種安全的類似注釋的機(jī)制,用來將任何的信息或元數(shù)據(jù)(metadata)與程序元素(類、方法、成員變量等)進(jìn)行關(guān)聯(lián)。為程序的元素(類、方法、成員變量)加上更直觀、更明了的說明,這些說明信息是與程序的業(yè)務(wù)邏輯無關(guān),并且供指定的工具或框架使用。Annontation像一種修飾符一樣,應(yīng)用于包、類型、構(gòu)造方法、方法、成員變量、參數(shù)及本地變量的聲明語句中。

Java注解是附加在代碼中的一些元信息,用于一些工具在編譯、運行時進(jìn)行解析和使用,起到說明、配置的功能。注解不會也不能影響代碼的實際邏輯,僅僅起到輔助性的作用。

一般我們自定義一個注解的操作是這樣的:

public @interface MyAnnotation {
}

如果說我們需要給他加上參數(shù),那么大概是這樣的

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
public @interface MyAnnotation {
    public int age() default 18;
    String name() ;
    String [] books();
}

我們可以關(guān)注到上面有些我們不曾見過的注解,而這類注解,統(tǒng)稱為元注解 ,我們可以大概來看一下

@Document

是被用來指定自定義注解是否能隨著被定義的java文件生成到JavaDoc文檔當(dāng)中。

@Target

是專門用來限定某個自定義注解能夠被應(yīng)用在哪些Java元素上面的,不定義說明可以放在任何元素上。

上面這個 Target這玩意有個枚舉,可以清晰的看出來,他的 屬性

使用枚舉類ElementType來定義

public enum ElementType {
    /** 類,接口(包括注解類型)或枚舉的聲明 */
    TYPE,
    /** 屬性的聲明 */
    FIELD,
    /** 方法的聲明 */
    METHOD,
    /** 方法形式參數(shù)聲明 */
    PARAMETER,
    /** 構(gòu)造方法的聲明 */
    CONSTRUCTOR,
    /** 局部變量聲明 */
    LOCAL_VARIABLE,
    /** 注解類型聲明 */
    ANNOTATION_TYPE,
    /** 包的聲明 */
    PACKAGE
}

@Retention

即用來修飾自定義注解的生命周期。

使用了RetentionPolicy枚舉類型定義了三個階段

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     * (注解將被編譯器丟棄)
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     * (注解將被編譯器記錄在class文件中,但在運行時不會被虛擬機(jī)保留,這是一個默認(rèn)的行為)
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     * (注解將被編譯器記錄在class文件中,而且在運行時會被虛擬機(jī)保留,因此它們能通過反射被讀取到)
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

@Inherited

允許子類繼承父類中的注解

注解的注意事項

1.訪問修飾符必須為public,不寫默認(rèn)為public;

2.該元素的類型只能是基本數(shù)據(jù)類型、String、Class、枚舉類型、注解類型(體現(xiàn)了注解的嵌套效果)以及上述類型的一位數(shù)組;

3.該元素的名稱一般定義為名詞,如果注解中只有一個元素,請把名字起為value(后面使用會帶來便利操作);

4.()不是定義方法參數(shù)的地方,也不能在括號中定義任何參數(shù),僅僅只是一個特殊的語法;

5.default代表默認(rèn)值,值必須和第2點定義的類型一致;

6.如果沒有默認(rèn)值,代表后續(xù)使用注解時必須給該類型元素賦值。

注解的本質(zhì)

所有的Java注解都基于Annotation接口。但是,手動定義一個繼承自Annotation接口的接口無效。要定義一個有效的Java注解,需要使用@interface關(guān)鍵字來聲明注解。Annotation接口本身只是一個普通的接口,并不定義任何注解類型。

public interface Annotation {  
    boolean equals(Object obj);
    /**
    * 獲取hashCode
    */
    int hashCode();
    
    String toString();
    /**
     *獲取注解類型 
     */
    Class<? extends Annotation> annotationType();
}

在Java中,所有的注解都是基于Annotation接口的,但是手動定義一個繼承自Annotation接口的接口并不會創(chuàng)建一個有效的注解。要定義有效的注解,需要使用特殊的關(guān)鍵字@interface來聲明注解類型。Annotation接口本身只是一個普通的接口,而不是一個定義注解的接口。因此,使用@interface聲明注解是定義Java注解的標(biāo)準(zhǔn)方法。

public @interface MyAnnotation1 {
}
public interface MyAnnotation2 extends Annotation  {
}
// javap -c TestAnnotation1.class
Compiled from "MyAnnotation1.java"                                                                 
public interface com.spirimark.corejava.annotation.MyAnnotation1 extends java.lang.annotation.Annotation {}
?
// javap -c TestAnnotation2.class
Compiled from "MyAnnotation2.java"                                                                 
public interface com.spirimark.corejava.annotation.MyAnnotation2 extends java.lang.annotation.Annotation {}

雖然Java中的所有注解都是基于Annotation接口,但即使接口本身支持多繼承,注解的定義仍無法使用繼承關(guān)鍵字來實現(xiàn)。定義注解的正確方式是使用特殊的關(guān)鍵字@interface聲明注解類型。

同時需要注意的是,通過@interface聲明的注解類型不支持繼承其他注解或接口。任何嘗試?yán)^承注解類型的操作都會導(dǎo)致編譯錯誤。

public @interface MyAnnotation1 {
}
/** 錯誤的定義,注解不能繼承注解 */
@interface MyAnnotation2 extends MyAnnotation1 {
}
/** 錯誤的定義,注解不能繼承接口 */
@interface MyAnnotation3 extends Annotation {
}

自定義注解使用

使用方式 1

自定義注解的玩法有很多,最常見的莫過于

  • 聲明注解
  • 通過反射讀取

但是上面這種一般現(xiàn)在在開發(fā)中不怎么常用,最常用的就是,我們通過 切面去在注解的前后進(jìn)行加載

創(chuàng)建注解

@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface BussinessLog {
 
    /**
     * 功能
     */
    BusinessTypeEnum value();
 
    /**
     * 是否保存請求的參數(shù)
     */
    boolean isSaveRequestData() default true;
 
    /**
     * 是否保存響應(yīng)的參數(shù)
     */
    boolean isSaveResponseData() default true;
}

設(shè)置枚舉

public enum BusinessTypeEnum {
    /**
     * 其它
     */
    OTHER,
 
    /**
     * 新增
     */
    INSERT,
 
    /**
     * 修改
     */
    UPDATE,
 
    /**
     * 刪除
     */
    DELETE,
 
    /**
     * 授權(quán)
     */
    GRANT,
 
    /**
     * 導(dǎo)出
     */
    EXPORT,
 
    /**
     * 導(dǎo)入
     */
    IMPORT,
}

創(chuàng)建切面操作

@Slf4j
@Aspect
@Component
public class LogConfig {
 
    @Autowired
    private IUxmLogService uxmLogService;
 
   /**
    * 后置通過,?標(biāo)?法正常執(zhí)?完畢時執(zhí)?
    *
    */
    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
        handleLog(joinPoint, controllerLog, null, jsonResult);
    }
 
   /**
    * 異常通知,?標(biāo)?法發(fā)?異常的時候執(zhí)?
    *
    */
    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
        handleLog(joinPoint, controllerLog, e, null);
    }
 
    protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
        try {
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            String title = methodSignature.getMethod().getAnnotation(ApiOperation.class).value();
            // 獲取當(dāng)前的用戶
            String userName = CurrentUser.getCurrentUserName();
 
            // *========數(shù)據(jù)庫日志=========*//
            UxmLog uxmLog = new UxmLog();
            uxmLog.setStatus(BaseConstant.YES);
            // 請求的地址
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            assert requestAttributes != null;
            HttpServletRequest request = requestAttributes.getRequest();
            String ip = getIpAddr(request);
            // 設(shè)置標(biāo)題
            uxmLog.setTitle(title);
            uxmLog.setOperIp(ip);
            uxmLog.setOperUrl(request.getRequestURI());
            uxmLog.setOperName(userName);
 
            if (e != null) {
                uxmLog.setStatus(BaseConstant.NO);
                uxmLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
            }
            // 設(shè)置方法名稱
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            uxmLog.setMethod(className + "." + methodName + "()");
            // 設(shè)置請求方式
            uxmLog.setRequestMethod(request.getMethod());
            // 處理設(shè)置注解上的參數(shù)
            getControllerMethodDescription(joinPoint, controllerLog, uxmLog, jsonResult, request);
            // 保存數(shù)據(jù)庫
            uxmLog.setOperTime(new Date());
            uxmLogService.save(uxmLog);
        } catch (Exception exp) {
            // 記錄本地異常日志
            log.error("==前置通知異常==");
            log.error("異常信息:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }
 
    public static String getIpAddr(HttpServletRequest request) {
        if (request == null) {
            return "unknown";
        }
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
 
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
 
    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, UxmLog uxmLog, Object jsonResult, HttpServletRequest request) throws Exception {
        // 設(shè)置action動作
        uxmLog.setBusinessType(log.value().ordinal());
        // 是否需要保存request,參數(shù)和值
        if (log.isSaveRequestData()) {
            // 獲取參數(shù)的信息,傳入到數(shù)據(jù)庫中。
            setRequestValue(joinPoint, uxmLog, request);
        }
        // 是否需要保存response,參數(shù)和值
        if (log.isSaveResponseData()) {
            uxmLog.setJsonResult(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000));
        }
    }
 
    private void setRequestValue(JoinPoint joinPoint, UxmLog uxmLog, HttpServletRequest request) throws Exception {
        String requestMethod = uxmLog.getRequestMethod();
        if (RequestMethod.PUT.name().equals(requestMethod) || RequestMethod.POST.name().equals(requestMethod)) {
            String params = argsArrayToString(joinPoint.getArgs());
            uxmLog.setOperParam(StringUtils.substring(params, 0, 2000));
        } else {
            Map<?, ?> paramsMap = (Map<?, ?>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
            uxmLog.setOperParam(StringUtils.substring(paramsMap.toString(), 0, 2000));
        }
    }
 
    private String argsArrayToString(Object[] paramsArray) {
        StringBuilder params = new StringBuilder();
        if (paramsArray != null && paramsArray.length > 0) {
            for (Object o : paramsArray) {
                if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) {
                    try {
                        Object jsonObj = JSON.toJSON(o);
                        params.append(jsonObj.toString()).append(" ");
                    } catch (Exception e) {
                        log.error(e.getMessage());
                    }
                }
            }
        }
        return params.toString().trim();
    }
 
    @SuppressWarnings("rawtypes")
    public boolean isFilterObject(final Object o) {
        Class<?> clazz = o.getClass();
        if (clazz.isArray()) {
            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
        } else if (Collection.class.isAssignableFrom(clazz)) {
            Collection collection = (Collection) o;
            for (Object value : collection) {
                return value instanceof MultipartFile;
            }
        } else if (Map.class.isAssignableFrom(clazz)) {
            Map map = (Map) o;
            for (Object value : map.entrySet()) {
                Map.Entry entry = (Map.Entry) value;
                return entry.getValue() instanceof MultipartFile;
            }
        }
        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
                || o instanceof BindingResult;
    }
}

這樣的話,我們就可以 在 項目當(dāng)中 去在標(biāo)注注解的前后去進(jìn)行輸出 日志

使用方式 2

我們可能還會在每次請求的時候去輸出日志,所以 我們也可以去定義一個 請求的 注解

@HttpLog 自動記錄Http日志

在很多時候我們要把一些接口的Http請求信息記錄到日志里面。通常原始的做法是利用日志框架如log4j,slf4j等,在方法里面打日志log.info(“xxxx”)。但是這樣的工作無疑是單調(diào)而又重復(fù)的,我們可以采用自定義注解+切面的來簡化這一工作。通常的日志記錄都在Controller里面進(jìn)行的比較多,我們可以實現(xiàn)這樣的效果:
我們自定義@HttpLog注解,作用域在類上,凡是打上了這個注解的Controller類里面的所有方法都會自動記錄Http日志。實現(xiàn)方式也很簡單,主要寫好切面表達(dá)式:

日志切面

下面代碼的意思,就是當(dāng)標(biāo)注了注解,我們通過 @Pointcut 定義了切入點, 當(dāng)標(biāo)注了注解,我們會在標(biāo)注注解的 前后進(jìn)行輸出 ,當(dāng)然也包含了 Spring 官方 自帶的注解 例如 RestController

// 切面表達(dá)式,描述所有所有需要記錄log的類,所有有@HttpLog 并且有 @Controller 或 @RestController 類都會被代理
    @Pointcut("@within(com.example.spiritmark.annotation.HttpLog) && (@within(org.springframework.web.bind.annotation.RestController) || @within(org.springframework.stereotype.Controller))")
    public void httpLog() {
    }

    @Before("httpLog()")
    public void preHandler(JoinPoint joinPoint) {
        startTime.set(System.currentTimeMillis());
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest httpServletRequest = servletRequestAttributes.getRequest();
        log.info("Current Url: {}", httpServletRequest.getRequestURI());
        log.info("Current Http Method: {}", httpServletRequest.getMethod());
        log.info("Current IP: {}", httpServletRequest.getRemoteAddr());
        Enumeration<String> headerNames = httpServletRequest.getHeaderNames();
        log.info("=======http headers=======");
        while (headerNames.hasMoreElements()) {
            String nextName = headerNames.nextElement();
            log.info(nextName.toUpperCase() + ": {}", httpServletRequest.getHeader(nextName));
        }
        log.info("======= header end =======");
        log.info("Current Class Method: {}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("Parms: {}", null != httpServletRequest.getQueryString() ? JSON.toJSONString(httpServletRequest.getQueryString().split("&")) : "EMPTY");

    }

    @AfterReturning(returning = "response", pointcut = "httpLog()")
    public void afterReturn(Object response) {
        log.info("Response: {}", JSON.toJSONString(response));
        log.info("Spend Time: [ {}", System.currentTimeMillis() - startTime.get() + " ms ]");

    }

@TimeStamp 自動注入時間戳

如果我們想通過自定義注解,在我們每次保存數(shù)據(jù)的時候,自動的幫我們將標(biāo)注注解的方法內(nèi)的時間戳字段轉(zhuǎn)換成 正常日期,我們就需要

我們的很多數(shù)據(jù)需要記錄時間戳,最常見的就是記錄created_at和updated_at,通常我們可以通常實體類中的setCreatedAt()方法來寫入當(dāng)前時間,然后通過ORM來插入到數(shù)據(jù)庫里,但是這樣的方法比較重復(fù)枯燥,給每個需要加上時間戳的類都要寫入時間戳很麻煩而且不小心會漏掉。

另一個思路是在數(shù)據(jù)庫里面設(shè)置默認(rèn)值,插入的時候由數(shù)據(jù)庫自動生成當(dāng)前時間戳,但是理想很豐滿,現(xiàn)實很骨感,在MySQL如果時間戳類型是datetime里即使你設(shè)置了默認(rèn)值為當(dāng)前時間也不會在時間戳為空時插入數(shù)據(jù)時自動生成,而是會在已有時間戳記錄的情況下更新時間戳為當(dāng)前時間,這并不是我們所需要的,比如我們不希望created_at每次更改記錄時都被刷新,另外的方法是將時間戳類型改為timestamp,這樣第一個類型為timestamp的字段會在值為空時自動生成,但是多個的話,后面的均不會自動生成。再有一種思路是,直接在sql里面用now()函數(shù)生成,比如created_at = now()。

但是這樣必須要寫sql,如果使用的不是主打sql流的orm不會太方便,比如hibernate之類的,并且也會加大sql語句的復(fù)雜度,同時sql的可移植性也會降低,比如sqlServer中就不支持now()函數(shù)。為了簡化這個問題,我們可以自定義@TimeStamp注解,打上該注解的方法的入?yún)⒗锩娴乃袑ο蠡蛘咧付▽ο罄锩嬉怯衧etCreatedAt、setUpdatedAt這樣的方法,便會自動注入時間戳,而無需手動注入,同時還可以指定只注入created_at或updated_at。實現(xiàn)主要代碼如下:

@Aspect
@Component
public class TimeStampAspect {

    @Pointcut("@annotation(com.example.spiritmark.annotation.TimeStamp)")
    public void timeStampPointcut() {}

    @Before("timeStampPointcut() && @annotation(timeStamp)")
    public void setTimestamp(JoinPoint joinPoint, TimeStamp timeStamp) {
        Long currentTime = System.currentTimeMillis();
        Class<?> type = timeStamp.type();
        Object[] args = joinPoint.getArgs();

        for (Object arg : args) {
            if (type.isInstance(arg)) {
                setTimestampForArg(arg, timeStamp);
            }
        }
    }

    private void setTimestampForArg(Object arg, TimeStamp timeStamp) {
        Date currentDate = new Date(System.currentTimeMillis());
        TimeStampRank rank = timeStamp.rank();
        Method[] methods = arg.getClass().getMethods();

        for (Method method : methods) {
            String methodName = method.getName();
            if (isSetter(methodName) && isRelevantSetter(methodName, rank)) {
                try {
                    method.invoke(arg, currentDate);
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private boolean isSetter(String methodName) {
        return methodName.startsWith("set") && methodName.length() > 3;
    }

    private boolean isRelevantSetter(String methodName, TimeStampRank rank) {
        if (rank.equals(TimeStampRank.FULL)) {
            return methodName.endsWith("At");
        }
        if (rank.equals(TimeStampRank.UPDATE)) {
            return methodName.startsWith("setUpdated");
        }
        if (rank.equals(TimeStampRank.CREATE)) {
            return methodName.startsWith("setCreated");
        }
        return false;
    }
}

1.使用@Aspect和@Component注解分別標(biāo)注切面和切面類,更符合AOP的實現(xiàn)方式。

2.將pointCut()和before()方法分別改名為timeStampPointcut()和setTimestamp(),更能表達(dá)它們的作用。

3.通過Class.isInstance(Object obj)方法,將原先的流操作改為了一個簡單的for循環(huán),使代碼更加簡潔。

4.將原先的setCurrentTime()方法改名為setTimestampForArg(),更能表達(dá)它的作用。

5.新增了兩個私有方法isSetter()和isRelevantSetter(),將原先在setTimestampForArg()中的邏輯分離出來,提高了代碼的可讀性和可維護(hù)性

到此這篇關(guān)于詳解Java中自定義注解的使用的文章就介紹到這了,更多相關(guān)Java自定義注解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java中transient關(guān)鍵字用法分析

    java中transient關(guān)鍵字用法分析

    這篇文章主要介紹了java中transient關(guān)鍵字用法,以實例形式分析了java中transient關(guān)鍵字的功能及使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-02-02
  • 如何根據(jù)帶賬號密碼的WSDL地址生成JAVA代碼

    如何根據(jù)帶賬號密碼的WSDL地址生成JAVA代碼

    這篇文章主要介紹了如何根據(jù)帶賬號密碼的WSDL地址生成JAVA代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-10-10
  • Jmeter參數(shù)化實現(xiàn)方法及應(yīng)用實例

    Jmeter參數(shù)化實現(xiàn)方法及應(yīng)用實例

    這篇文章主要介紹了Jmeter參數(shù)化實現(xiàn)方法及應(yīng)用實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-08-08
  • spring源碼學(xué)習(xí)之bean的初始化以及循環(huán)引用

    spring源碼學(xué)習(xí)之bean的初始化以及循環(huán)引用

    這篇文章主要給大家介紹了關(guān)于spring源碼學(xué)習(xí)之bean的初始化以及循環(huán)引用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • Spring?Boot?2.x升3.x的那些事

    Spring?Boot?2.x升3.x的那些事

    最近項目需求,準(zhǔn)備從Spring Boot 2.x升級到3.x,升級后發(fā)現(xiàn)編譯器報了一堆錯誤,本文主要介紹了Spring?Boot?2.x升3.x的那些事,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • java與JSON數(shù)據(jù)的轉(zhuǎn)換實例詳解

    java與JSON數(shù)據(jù)的轉(zhuǎn)換實例詳解

    這篇文章主要介紹了java與JSON數(shù)據(jù)的轉(zhuǎn)換實例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • Spring?Bean注冊與注入實現(xiàn)方法詳解

    Spring?Bean注冊與注入實現(xiàn)方法詳解

    首先,要學(xué)習(xí)Spring中的Bean的注入方式,就要先了解什么是依賴注入。依賴注入是指:讓調(diào)用類對某一接口的實現(xiàn)類的實現(xiàn)類的依賴關(guān)系由第三方注入,以此來消除調(diào)用類對某一接口實現(xiàn)類的依賴。Spring容器中支持的依賴注入方式主要有屬性注入、構(gòu)造函數(shù)注入、工廠方法注入
    2022-10-10
  • Spring Boot 2.0.0 終于正式發(fā)布-重大修訂版本

    Spring Boot 2.0.0 終于正式發(fā)布-重大修訂版本

    北京時間 2018 年 3 月 1 日早上,如約發(fā)布的 Spring Boot 2.0 在同步至 Maven 倉庫時出現(xiàn)問題,導(dǎo)致在 GitHub 上發(fā)布的 v2.0.0.RELEASE 被撤回
    2018-03-03
  • Java8中LocalDateTime與時間戳timestamp的互相轉(zhuǎn)換

    Java8中LocalDateTime與時間戳timestamp的互相轉(zhuǎn)換

    這篇文章主要給大家介紹了關(guān)于Java8中LocalDateTime與時間戳timestamp的互相轉(zhuǎn)換,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Java8-Stream流操作List去重問題

    Java8-Stream流操作List去重問題

    這篇文章主要介紹了Java8-Stream流操作List去重問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11

最新評論