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

Java中的SpringAOP、代理模式、常用AspectJ注解詳解

 更新時間:2023年09月08日 10:16:01   作者:洞之蟬  
這篇文章主要介紹了Java中的SpringAOP、代理模式、常用AspectJ注解詳解,Spring提供了面向切面編程的豐富支持,允許通過分離應(yīng)用的業(yè)務(wù)邏輯與系統(tǒng)級服務(wù),例如審計和事務(wù)管理進(jìn)行內(nèi)聚性的開發(fā),需要的朋友可以參考下

一、AOP簡述

回到主題,何為AOP?AOP即面向切面編程——Spring提供了面向切面編程的豐富支持,允許通過分離應(yīng)用的業(yè)務(wù)邏輯與系統(tǒng)級服務(wù)(例如審計(auditing)和事務(wù)(transaction)管理)進(jìn)行內(nèi)聚性的開發(fā)。

應(yīng)用對象只實現(xiàn)它們應(yīng)該做的——完成業(yè)務(wù)邏輯——僅此而已。

它們并不負(fù)責(zé)(甚至是意識)其它的系統(tǒng)級關(guān)注點,例如日志或事務(wù)支持。

如下圖,可以很直接明了的展示整個AOP的過程:

1.1 一些基本概念

通知(Adivce)

通知有5種類型:

我們可能會問,那通知對應(yīng)系統(tǒng)中的代碼是一個方法、對象、類、還是接口什么的呢?

我想說一點,其實都不是,你可以理解通知就是對應(yīng)我們?nèi)粘I钪兴f的通知,比如‘某某人,你2019年9月1號來學(xué)校報個到’,通知更多地體現(xiàn)一種告訴我們(告訴系統(tǒng)何)何時執(zhí)行,規(guī)定一個時間,在系統(tǒng)運行中的某個時間點(比如拋異常啦!方法執(zhí)行前啦!), 并非對應(yīng)代碼中的方法!并非對應(yīng)代碼中的方法!并非對應(yīng)代碼中的方法!

  • Before 在方法被調(diào)用之前調(diào)用
  • After 在方法完成后調(diào)用通知,無論方法是否執(zhí)行成功
  • After-returning 在方法成功執(zhí)行之后調(diào)用通知
  • After-throwing 在方法拋出異常后調(diào)用通知
  • Around 通知了好、包含了被通知的方法,在被通知的方法調(diào)用之前后調(diào)用之后執(zhí)行自定義的行為
  • 切點(Pointcut)
    • 切點在Spring AOP中確實是對應(yīng)系統(tǒng)中的方法。但是這個方法是定義在切面中的方法,一般和通知一起使用,一起組成了切面。
  • 連接點(Join point)
    • 比如:方法調(diào)用、方法執(zhí)行、字段設(shè)置/獲取、異常處理執(zhí)行、類初始化、甚至是 for 循環(huán)中的某個點 理論上, 程序執(zhí)行過程中的任何時點都可以作為作為織入點, 而所有這些執(zhí)行時點都是 Joint point 但 Spring AOP 目前僅支持方法執(zhí)行 (method execution) 也可以這樣理解,連接點就是你準(zhǔn)備在系統(tǒng)中執(zhí)行切點和切入通知的地方(一般是一個方法,一個字段)
  • 切面(Aspect)
    • 切面是切點和通知的集合,一般單獨作為一個類。通知和切點共同定義了關(guān)于切面的全部內(nèi)容,它是什么時候,在何時和何處完成功能。
  • 引入(Introduction)
    • 引用允許我們向現(xiàn)有的類添加新的方法或者屬性
  • 織入(Weaving)
    • 組裝方面來創(chuàng)建一個被通知對象。這可以在編譯時完成(例如使用AspectJ編譯器),也可以在運行時完成。Spring和其他純Java AOP框架一樣,在運行時完成織入。

二、代理模式

首先AOP思想的實現(xiàn)一般都是基于代理模式,在JAVA中一般采用JDK動態(tài)代理模式,但是我們都知道,JDK動態(tài)代理模式只能代理接口,如果要代理類那么就不行了。

因此,Spring AOP 會這樣子來進(jìn)行切換,因為Spring AOP 同時支持 CGLIB、ASPECTJ、JDK動態(tài)代理,當(dāng)你的真實對象有實現(xiàn)接口時,Spring AOP會默認(rèn)采用JDK動態(tài)代理,否則采用cglib代理。

  • 如果目標(biāo)對象的實現(xiàn)類實現(xiàn)了接口,Spring AOP 將會采用 JDK 動態(tài)代理來生成 AOP 代理類;
  • 如果目標(biāo)對象的實現(xiàn)類沒有實現(xiàn)接口,Spring AOP 將會采用 CGLIB 來生成 AOP 代理類——不過這個選擇過程對開發(fā)者完全透明、開發(fā)者也無需關(guān)心。

這里簡單說說代理模式,代理模式的UML類圖如下:

2.1 靜態(tài)代理

//接口類:
interface Person {
    void speak();
}
//真實實體類:
class Actor implements Person {
    private String content;
    public Actor(String content) {
        this.content = content;
    }
    @Override
    public void speak() {
        System.out.println(this.content);
    }
}
//代理類:
class Agent implements Person {
    private Actor actor;
    private String before;
    private String after;
    public Agent(Actor actor, String before, String after) {
        this.actor = actor;
        this.before = before;
        this.after = after;
    }
    @Override
    public void speak() {
        //before speak
        System.out.println("Before actor speak, Agent say: " + before);
        //real speak
        this.actor.speak();
        //after speak
        System.out.println("After actor speak, Agent say: " + after);
    }
}
//測試方法:
public class StaticProxy {
    public static void main(String[] args) {
        Actor actor = new Actor("I am a famous actor!");
        Agent agent = new Agent(actor, "Hello I am an agent.", "That's all!");
        agent.speak();
    }
}

2.2 動態(tài)代理

在講JDK的動態(tài)代理方法之前,不妨先想想如果讓你來實現(xiàn)一個可以任意類的任意方法的代理類,該怎么實現(xiàn)?有個很naive的做法,通過反射獲得Class和Method,再調(diào)用該方法,并且實現(xiàn)一些代理的方法。我嘗試了一下,很快就發(fā)現(xiàn)問題所在了。于是乎,還是使用JDK的動態(tài)代理接口吧。

JDK自帶方法

首先介紹一下最核心的一個接口和一個方法:

首先是java.lang.reflect包里的InvocationHandler接口:

    public interface InvocationHandler {
        public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
    }

我們對于被代理的類的操作都會由該接口中的invoke方法實現(xiàn),其中的參數(shù)的含義分別是:

  • proxy:被代理的類的實例
  • method:調(diào)用被代理的類的方法
  • args:該方法需要的參數(shù)

使用方法首先是需要實現(xiàn)該接口,并且我們可以在invoke方法中調(diào)用被代理類的方法并獲得返回值,自然也可以在調(diào)用該方法的前后去做一些額外的事情,從而實現(xiàn)動態(tài)代理,下面的例子會詳細(xì)寫到。

另外一個很重要的靜態(tài)方法是java.lang.reflect包中的Proxy類的newProxyInstance方法:

 public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException

其中的參數(shù)含義如下:

  • loader:被代理的類的類加載器
  • interfaces:被代理類的接口數(shù)組
  • invocationHandler:就是剛剛介紹的調(diào)用處理器類的對象實例

該方法會返回一個被修改過的類的實例,從而可以自由的調(diào)用該實例的方法。下面是一個實際例子。

Fruit接口:
    public interface Fruit {
        public void show();
    }
Apple實現(xiàn)Fruit接口:
    public class Apple implements Fruit{
        @Override
        public void show() {
            System.out.println("<<<);
        }
    }
代理類Agent.java:
    public class DynamicAgent {
        //實現(xiàn)InvocationHandler接口,并且可以初始化被代理類的對象
        static class MyHandler implements InvocationHandler {
            private Object proxy;
            public MyHandler(Object proxy) {
                this.proxy = proxy;
            }
            //自定義invoke方法
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(">>>>before invoking");
                //真正調(diào)用方法的地方
                Object ret = method.invoke(this.proxy, args);
                System.out.println(">>>>after invoking");
                return ret;
            }
        }
        //返回一個被修改過的對象
        public static Object agent(Class interfaceClazz, Object proxy) {
            return Proxy.newProxyInstance(interfaceClazz.getClassLoader(), new Class[]{interfaceClazz},
                    new MyHandler(proxy));
        }    
    }
測試類:
    public class ReflectTest {
        public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
            //注意一定要返回接口,不能返回實現(xiàn)類否則會報錯
            Fruit fruit = (Fruit) DynamicAgent.agent(Fruit.class, new Apple());
            fruit.show();
        }
    }

結(jié)果:

可以看到對于不同的實現(xiàn)類來說,可以用同一個動態(tài)代理類來進(jìn)行代理,實現(xiàn)了“一次編寫到處代理”的效果。

但是這種方法有個缺點,就是被代理的類一定要是實現(xiàn)了某個接口的,這很大程度限制了本方法的使用場景。下面還有另外一個使用了CGlib增強庫的方法。

2.3 CGLIB庫的方法

CGlib是一個字節(jié)碼增強庫,為AOP等提供了底層支持。下面看看它是怎么實現(xiàn)動態(tài)代理的。

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGlibAgent implements MethodInterceptor {
    private Object proxy;
    public Object getInstance(Object proxy) {
        this.proxy = proxy;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.proxy.getClass());
        // 回調(diào)方法
        enhancer.setCallback(this);
        // 創(chuàng)建代理對象
        return enhancer.create();
    }
    //回調(diào)方法
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println(">>>>before invoking");
        //真正調(diào)用
        Object ret = methodProxy.invokeSuper(o, objects);
        System.out.println(">>>>after invoking");
        return ret;
    }
    public static void main(String[] args) {
        CGlibAgent cGlibAgent = new CGlibAgent();
        Apple apple = (Apple) cGlibAgent.getInstance(new Apple());
        apple.show();
    }
}

三、Spring中的AOP: @AspectJ

3.1 @AspectJ 由來

AspectJ是一個AOP框架,它能夠?qū)ava代碼進(jìn)行AOP編譯(一般在編譯期進(jìn)行),讓java代碼具有AspectJ的AOP功能(當(dāng)然需要特殊的編譯器),可以這樣說AspectJ是目前實現(xiàn)AOP框架中最成熟,功能最豐富的語言,更幸運的是,AspectJ與java程序完全兼容,幾乎是無縫關(guān)聯(lián),因此對于有java編程基礎(chǔ)的工程師,上手和使用都非常容易。

其實AspectJ單獨就是一門語言,它需要專門的編譯器(ajc編譯器). Spring AOP 與ApectJ的目的一致,都是為了統(tǒng)一處理橫切業(yè)務(wù),但與AspectJ不同的是,Spring AOP并不嘗試提供完整的AOP功能(即使它完全可以實現(xiàn)),Spring AOP 更注重的是與Spring IOC容器的結(jié)合,并結(jié)合該優(yōu)勢來解決橫切業(yè)務(wù)的問題,因此在AOP的功能完善方面,相對來說AspectJ具有更大的優(yōu)勢,同時,Spring注意到AspectJ在AOP的實現(xiàn)方式上依賴于特殊編譯器(ajc編譯器),因此Spring很機智回避了這點,轉(zhuǎn)向采用動態(tài)代理技術(shù)的實現(xiàn)原理來構(gòu)建Spring AOP的內(nèi)部機制(動態(tài)織入),這是與AspectJ(靜態(tài)織入)最根本的區(qū)別。在AspectJ 1.5后,引入@Aspect形式的注解風(fēng)格的開發(fā),Spring也非常快地跟進(jìn)了這種方式,因此Spring 2.0后便使用了與AspectJ一樣的注解。請注意,Spring 只是使用了與 AspectJ 5 一樣的注解,但仍然沒有使用 AspectJ 的編譯器,底層依是動態(tài)代理技術(shù)的實現(xiàn),因此并不依賴于 AspectJ 的編譯器。

所以,Spring AOP雖然是使用了AspectJ那一套注解,其實實現(xiàn)AOP的底層是使用了動態(tài)代理(JDK或者CGLib)來動態(tài)植入。

3.2 舉個栗子

小狗類,會說話:

?
public class Dog {
    private String name;
    public void say(){
        System.out.println(name + "在汪汪叫!...");
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
切面類:
@Aspect //聲明自己是一個切面類
public class MyAspect {
    /**
     * 前置通知
     */
     //@Before是增強中的方位
     // @Before括號中的就是切入點了
     //before()就是傳說的增強(建言):說白了,就是要干啥事.
    @Before("execution(* com.zdy..*(..))")
    public void before(){
        System.out.println("前置通知....");
    }
}
?

這個類是重點,先用@Aspect聲明自己是切面類,然后before()為增強,@Before(方位)+切入點可以具體定位到具體某個類的某個方法的方位. Spring配置文件:

//開啟AspectJ功能.
    <aop:aspectj-autoproxy />
    <bean id="dog" class="com.zdy.Dog" />
    <bean name="myAspect" class="com.zdy.MyAspect"/>
然后Main方法:
        ApplicationContext ac =new ClassPathXmlApplicationContext("applicationContext.xml");
        Dog dog =(Dog) ac.getBean("dog");
        System.out.println(dog.getClass());
        dog.say();

輸出結(jié)果:

class com.zdy.Dog$$EnhancerBySpringCGLIB$$80a9ee5f
前置通知....
null在汪汪叫!...

說白了,就是把切面類丟到容器,開啟一個AdpectJ的功能,Spring AOP就會根據(jù)切面類中的(@Before+切入點)定位好具體的類的某個方法(我這里定義的是com.zdy包下的所有類的所有方法),然后把增強before()切入進(jìn)去.

3.3 舉個Spring Boot中的栗子

這個栗子很實用,關(guān)于Aop做切面去統(tǒng)一處理Web請求的日志:

@Aspect
@Component
public class WebLogAspect {
    private Logger logger = Logger.getLogger(getClass());
    @Pointcut("execution(public * com.didispace.web..*.*(..))")
    public void webLog(){}
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 接收到請求,記錄請求內(nèi)容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 記錄下請求內(nèi)容
        logger.info("URL : " + request.getRequestURL().toString());
        logger.info("HTTP_METHOD : " + request.getMethod());
        logger.info("IP : " + request.getRemoteAddr());
        logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
    }
    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 處理完請求,返回內(nèi)容
        logger.info("RESPONSE : " + ret);
    }
}

可以看上面的例子,通過 @Pointcut 定義的切入點為 com.didispace.web 包下的所有函數(shù)(對web層所有請求處理做切入點),然后通過 @Before 實現(xiàn),對請求內(nèi)容的日志記錄(本文只是說明過程,可以根據(jù)需要調(diào)整內(nèi)容),最后通過 @AfterReturning 記錄請求返回的對象。

通過運行程序并訪問: //localhost:8080/hello?name=didi ,可以獲得下面的日志輸出

2016-05-19 13:42:13,156  INFO WebLogAspect:41 - URL : http://localhost:8080/hello
2016-05-19 13:42:13,156  INFO WebLogAspect:42 - HTTP_METHOD : http://localhost:8080/hello
2016-05-19 13:42:13,157  INFO WebLogAspect:43 - IP : 0:0:0:0:0:0:0:1
2016-05-19 13:42:13,160  INFO WebLogAspect:44 - CLASS_METHOD : com.didispace.web.HelloController.hello
2016-05-19 13:42:13,160  INFO WebLogAspect:45 - ARGS : [didi]
2016-05-19 13:42:13,170  INFO WebLogAspect:52 - RESPONSE:Hello didi

3.4 Spring AOP支持的幾種AspectJ注解

  • 前置通知@Before: 前置通知通過@Before注解進(jìn)行標(biāo)注,并可直接傳入切點表達(dá)式的值,該通知在目標(biāo)函數(shù)執(zhí)行前執(zhí)行,注意JoinPoint,是Spring提供的靜態(tài)變量,通過joinPoint 參數(shù),可以獲取目標(biāo)對象的信息,如類名稱,方法參數(shù),方法名稱等,該參數(shù)是可選的。
@Before("execution(...)")
public void before(JoinPoint joinPoint){
    System.out.println("...");
}
  • 后置通知@AfterReturning: 通過@AfterReturning注解進(jìn)行標(biāo)注,該函數(shù)在目標(biāo)函數(shù)執(zhí)行完成后執(zhí)行,并可以獲取到目標(biāo)函數(shù)最終的返回值returnVal,當(dāng)目標(biāo)函數(shù)沒有返回值時,returnVal將返回null,必須通過returning = “returnVal”注明參數(shù)的名稱而且必須與通知函數(shù)的參數(shù)名稱相同。請注意,在任何通知中這些參數(shù)都是可選的,需要使用時直接填寫即可,不需要使用時,可以完成不用聲明出來。
@AfterReturning(value="execution(...)",returning = "returnVal")
public void AfterReturning(JoinPoint joinPoint,Object returnVal){
   System.out.println("我是后置通知...returnVal+"+returnVal);
}
  • 異常通知 @AfterThrowing:該通知只有在異常時才會被觸發(fā),并由throwing來聲明一個接收異常信息的變量,同樣異常通知也用于Joinpoint參數(shù),需要時加上即可.
@AfterThrowing(value="execution(....)",throwing = "e")
public void afterThrowable(Throwable e){
  System.out.println("出現(xiàn)異常:msg="+e.getMessage());
}
  • 最終通知 @After:該通知有點類似于finally代碼塊,只要應(yīng)用了無論什么情況下都會執(zhí)行.
@After("execution(...)")
public void after(JoinPoint joinPoint) {
    System.out.println("最終通知....");
}
  • 環(huán)繞通知 @Around: 環(huán)繞通知既可以在目標(biāo)方法前執(zhí)行也可在目標(biāo)方法之后執(zhí)行,更重要的是環(huán)繞通知可以控制目標(biāo)方法是否指向執(zhí)行,但即使如此,我們應(yīng)該盡量以最簡單的方式滿足需求,在僅需在目標(biāo)方法前執(zhí)行時,應(yīng)該采用前置通知而非環(huán)繞通知。案例代碼如下第一個參數(shù)必須是ProceedingJoinPoint,通過該對象的proceed()方法來執(zhí)行目標(biāo)函數(shù),proceed()的返回值就是環(huán)繞通知的返回值。同樣的,ProceedingJoinPoint對象也是可以獲取目標(biāo)對象的信息,如類名稱,方法參數(shù),方法名稱等等
@Around("execution(...)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("我是環(huán)繞通知前....");
    //執(zhí)行目標(biāo)函數(shù)
    Object obj= (Object) joinPoint.proceed();
    System.out.println("我是環(huán)繞通知后....");
    return obj;
}

然后說下一直用"…"忽略掉的切入點表達(dá)式,這個表達(dá)式可以不是exection(…),還有其他的一些,我就不說了,說最常用的execution:

?
//scope :方法作用域,如public,private,protect
//returnt-type:方法返回值類型
//fully-qualified-class-name:方法所在類的完全限定名稱
//parameters 方法參數(shù)
execution(<scope> <return-type> <fully-qualified-class-name>.*(parameters))
<fully-qualified-class-name>.*(parameters)
?

注意這一塊,如果沒有精確到class-name,而是到包名就停止了,要用兩個"…"來表示包下的任意類:

  • execution(* com.zdy…*(…)):com.zdy包下所有類的所有方法.
  • execution(* com.zdy.Dog.*(…)): Dog類下的所有方法.

具體詳細(xì)語法,大家如果有需求自行g(shù)oogle了,我最常用的就是這倆了。要么按照包來定位,要么按照具體類來定位.

在使用切入點時,還可以抽出來一個@Pointcut來供使用:

/**
 * 使用Pointcut定義切點
 */
@Pointcut("execution(...)")
private void myPointcut(){}
/**
 * 應(yīng)用切入點函數(shù)
 */
@After(value="myPointcut()")
public void afterDemo(){
    System.out.println("最終通知....");
}

可以避免重復(fù)的execution在不同的注解里寫很多遍…

3.5 AOP切面的優(yōu)先級

由于通過AOP實現(xiàn),程序得到了很好的解耦,但是也會帶來一些問題,比如:我們可能會對Web層做多個切面,校驗用戶,校驗頭信息等等,這個時候經(jīng)常會碰到切面的處理順序問題。

所以,我們需要定義每個切面的優(yōu)先級,我們需要@Order(i)注解來標(biāo)識切面的優(yōu)先級。i的值越小,優(yōu)先級越高。假設(shè)我們還有一個切面是CheckNameAspect用來校驗name必須為derry,我們?yōu)槠湓O(shè)置@Order(10),而上文中WebLogAspect設(shè)置為@Order(5),所以WebLogAspect有更高的優(yōu)先級,這個時候執(zhí)行順序是這樣的:

  • 在@Before中優(yōu)先執(zhí)行@Order(5)的內(nèi)容,再執(zhí)行@Order(10)的內(nèi)容
  • 在@After和@AfterReturning中優(yōu)先執(zhí)行@Order(10)的內(nèi)容,再執(zhí)行@Order(5)的內(nèi)容

所以我們可以這樣子總結(jié):

  • 在切入點前的操作,按order的值由小到大執(zhí)行
  • 在切入點后的操作,按order的值由大到小執(zhí)行

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

相關(guān)文章

  • java中的實體類時間格式化

    java中的實體類時間格式化

    這篇文章主要介紹了java中的實體類時間格式化方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • SpringBoot深入理解之內(nèi)置web容器及配置的總結(jié)

    SpringBoot深入理解之內(nèi)置web容器及配置的總結(jié)

    今天小編就為大家分享一篇關(guān)于SpringBoot深入理解之內(nèi)置web容器及配置的總結(jié),小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • Kotlin實現(xiàn)靜態(tài)方法

    Kotlin實現(xiàn)靜態(tài)方法

    這篇文章主要介紹了Kotlin實現(xiàn)靜態(tài)方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • spring中前端明明傳了值后端卻接收不到問題解決辦法

    spring中前端明明傳了值后端卻接收不到問題解決辦法

    在學(xué)習(xí)Spring的時候遇到了一個問題,后臺一直接收不到前臺傳遞過來的參數(shù),耽誤了好長時間終于找到了原因,這篇文章主要給大家介紹了關(guān)于spring中前端明明傳了值后端卻接收不到問題的解決辦法,需要的朋友可以參考下
    2024-05-05
  • Scala可變參數(shù)列表,命名參數(shù)和參數(shù)缺省詳解

    Scala可變參數(shù)列表,命名參數(shù)和參數(shù)缺省詳解

    這篇文章主要介紹了Scala可變參數(shù)列表,命名參數(shù)和參數(shù)缺省詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • SpringCloud Feign 服務(wù)調(diào)用的實現(xiàn)

    SpringCloud Feign 服務(wù)調(diào)用的實現(xiàn)

    Feign是一個聲明性web服務(wù)客戶端。本文記錄多個服務(wù)之間使用Feign調(diào)用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • SpringBoot源碼之Bean的生命周期

    SpringBoot源碼之Bean的生命周期

    spring的bean的生命周期主要是創(chuàng)建bean的過程,一個bean的生命周期主要是4個步驟,實例化,屬性注入,初始化,銷毀,本文詳細(xì)介紹了bean的生命周期,感興趣的小伙伴可以參考閱讀
    2023-04-04
  • 深入淺出理解Java泛型的使用

    深入淺出理解Java泛型的使用

    這篇文章主要介紹了深入淺出理解Java泛型的使用,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • @ControllerAdvice 用法解析

    @ControllerAdvice 用法解析

    @ControllerAdvice就是@Controller 的增強版,@ControllerAdvice主要用來處理全局?jǐn)?shù)據(jù),一般搭配@ExceptionHandler、@ModelAttribute以及@InitBinder使用,這篇文章主要介紹了@ControllerAdvice 用法,需要的朋友可以參考下
    2022-11-11
  • 如何使用java判斷是不是數(shù)字

    如何使用java判斷是不是數(shù)字

    這篇文章主要給大家介紹了關(guān)于如何使用java判斷是不是數(shù)字的相關(guān)資料,判斷一個字符串是否為數(shù)字是Java開發(fā)中很常見的業(yè)務(wù)需求,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-06-06

最新評論