Spring基礎使用

Spring基礎使用

Spring IOC

  • 新建工程
    新建maven工程,然后在pom.xml中添加如下依賴:
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.7</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
        </dependency>
  • 測試IOCbean注入
    新建三個服務類:ServiceA, ServiceB, ServiceC
package com.test.service;

/**
 * @author felix
 */
public class ServiceA {
    private ServiceB serviceB;

    public void setServiceB(ServiceB serviceB) {
        this.serviceB = serviceB;
    }

    public void doSth(){
        System.out.println("serviceA doSth");
    }
}
package com.test.service;

/**
 * @author felix
 */
public class ServiceB {
    private ServiceC serviceC;

    public void setServiceC(ServiceC serviceC) {
        this.serviceC = serviceC;
    }

    public void doSth() {
        System.out.println("ServiceB doSth");
    }
}

package com.test.service;

/**
 * @author felix
 */
public class ServiceC {
    private ServiceA serviceA;

    public void setServiceA(ServiceA serviceA) {
        this.serviceA = serviceA;
    }

    public void doSth() {
        System.out.println("ServiceC doSth");
    }
}

新增beans.xml,內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean name="serviceA" class="com.test.service.ServiceA">
        <property name="serviceB" ref="serviceB"/>
    </bean>

    <bean name="serviceB" class="com.test.service.ServiceB">
        <property name="serviceC" ref="serviceC"/>
    </bean>

    <bean name="serviceC" class="com.test.service.ServiceC">
        <property name="serviceA" ref="serviceA"/>
    </bean>
</beans>

注意:bean的依賴項配置在property標簽中,同時需要再依賴方定義成員變量镣衡,并寫好setter方法侨赡,如果不生成setter暴匠,Spring默認是無法注入進來的
新增測試類:

package com.test;

import com.test.service.ServiceA;
import com.test.service.ServiceB;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringFrameworkTests {
    private ApplicationContext applicationContext;

    @Before
    public void init() {
        applicationContext = new ClassPathXmlApplicationContext("beans.xml");
    }

    @Test
    public void testIoc() {
        ServiceA serviceA = (ServiceA) applicationContext.getBean("serviceA");
        serviceA.doSth();
        ServiceB serviceB = applicationContext.getBean(ServiceB.class);
        serviceB.doSth();
    }
}

執(zhí)行單元測試涩蜘,結果如下:

serviceA doSth
ServiceB doSth
  • 屬性注入
    在beans.xml中新增如下配置:
    <context:property-placeholder location="db.properties"/>
    <bean name="config" class="com.test.service.Config">
        <property name="driverClass" value="${db.driverClass}"/>
        <property name="jdbcUrl" value="${db.jdbcUrl}"/>
        <property name="username" value="${db.username}"/>
        <property name="password" value="ccc"/>
        <property name="infoMap" ref="infoMap"/>
        <property name="properties" ref="properties"/>
    </bean>

    <util:map id="infoMap">
        <entry key="a" value="a"/>
        <entry key="b" value="b"/>
    </util:map>

    <util:properties id="properties">
        <prop key="p1">1</prop>
        <prop key="p2">c</prop>
    </util:properties>

新增db.propertis

db.driverClass=com.mysql.jdbc.Driver
db.jdbcUrl=///spring-learning
db.username=root
db.password=root

新增Config.java

package com.test.service;

import java.util.Map;
import java.util.Properties;

public class Config {
    private String driverClass;

    private String jdbcUrl;

    private String username;

    private String password;

    private Map<String, Object> infoMap;

    private Properties properties;

    @Override
    public String toString() {
        return "Config{" + "driverClass='" + driverClass + '\'' + ", jdbcUrl='" + jdbcUrl + '\''
                + ", username='" + username + '\'' + ", password='" + password + '\'' + ", infoMap="
                + infoMap + ", properties=" + properties + '}';
    }

    public String getDriverClass() {
        return driverClass;
    }

    public void setDriverClass(String driverClass) {
        this.driverClass = driverClass;
    }

    public String getJdbcUrl() {
        return jdbcUrl;
    }

    public void setJdbcUrl(String jdbcUrl) {
        this.jdbcUrl = jdbcUrl;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Map<String, Object> getInfoMap() {
        return infoMap;
    }

    public void setInfoMap(Map<String, Object> infoMap) {
        this.infoMap = infoMap;
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}

新增測試方法:

    @Test
    public void testIocProperties() {
        Config config = applicationContext.getBean(Config.class);
        System.out.println(config.toString());
    }

執(zhí)行結果:

Config{driverClass='com.mysql.jdbc.Driver', jdbcUrl='///spring-learning', username='root', password='ccc', infoMap={a=a, b=b}, properties={p2=c, p1=1}}

Spring可以注入的屬性值有:
基礎數(shù)據(jù)類型,bean對象占贫,Properties, Map, Set等,其中Properties,Map,Set我們需要用對應的標簽單獨配置,property 的value部分填入對應的id即可肢簿。

測試AOP
在beans.xml中新增如下配置:

    <bean id="logUtil" class="com.test.aop.LogUtil"/>
    <aop:config>
        <aop:aspect id="logAdvice" ref="logUtil">
            <aop:pointcut id="doSthPointCut"
                          expression="execution(public * com.test.service.ServiceA.doSth())"/>
            <aop:before method="printBefore"
                        pointcut-ref="doSthPointCut"/>
            <aop:after method="printAfter"
                       pointcut-ref="doSthPointCut"/>
            <aop:after-returning method="printAfterReturning"
                                 pointcut-ref="doSthPointCut"/>
            <aop:after-throwing method="afterThrowing"
                                pointcut-ref="doSthPointCut"/>
            <aop:around method="around" pointcut-ref="doSthPointCut"/>
        </aop:aspect>
    </aop:config>

新增LogUtil.java

package com.test.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.Pointcut;

public class LogUtil {
    /**
     * 前面打印
     */
    public void printBefore() {
        System.out.println("print info from LogUtil.printBefore");
    }

    /**
     * 后面打印
     */
    public void printAfter() {
        System.out.println("print info from LogUtil.printAfter");
    }

    /**
     * 后面打印
     */
    public void printAfterReturning() {
        System.out.println("print info from LogUtil.printAfterReturning");
    }

    /**
     * 后面打印
     */
    public void afterThrowing() {
        System.out.println("print info from LogUtil.afterThrowing");
    }

    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("---around before----");
        Object result = joinPoint.proceed();
        System.out.println(result);
        System.out.println("---around after----");
    }
}

改造serviceA的doSth方法:

    public String doSth(){
        System.out.println("serviceA doSth");
        // throw new RuntimeException("an exception ");
        return "hello";
    }

啟動第一步中測試IOC BEAN的測試方法

@Test
    public void testSimpleIoc() {
        ServiceA serviceA = (ServiceA) applicationContext.getBean("serviceA");
        serviceA.doSth();
        ServiceB serviceB = applicationContext.getBean(ServiceB.class);
        serviceB.doSth();
    }

輸出結果如下:

print info from LogUtil.printBefore
---around before----
serviceA doSth
hello
---around after----
print info from LogUtil.printAfterReturning
print info from LogUtil.printAfter
ServiceB doSth

在ServiceA.doSth中拋出異常

public String doSth(){
        System.out.println("serviceA doSth");
        throw new RuntimeException("an exception ");
        // return "hello";
    }

執(zhí)行結果如下:

print info from LogUtil.printBefore
---around before----
serviceA doSth
print info from LogUtil.afterThrowing
print info from LogUtil.printAfter

java.lang.RuntimeException: an exception
一堆異常信息靶剑。。池充。
  • aspec指定切面邏輯類桩引,也即是使用被用來處理切面的邏輯達到增強其他方法的目的那個類
  • pointcut指定切入點是什么,往往是某個類或者某些類的某些方法收夸。也即是配置我們哪些類的哪些方法需要被增強坑匠。
  • before, after, afterReturning, afterThrowing, around 分別表示橫切邏輯代碼所執(zhí)行的時機。也即我們希望在目標方法執(zhí)行的什么時候進行增強卧惜。
    從測試結果來分析厘灼,這幾個切入時機執(zhí)行順序分別為:
    before > around前置處理 > 目標方法邏輯(around joinPoint.proceed) > around后置處理>afterReturing / afterThrowing > after
    注:afterReturning與afterThrowing只會執(zhí)行其中之一夹纫,因為目標邏輯代碼要么正常執(zhí)行完成,要么出現(xiàn)異常

Spring基于注解的開發(fā)

修改測試代碼前兩部分如下:

 @Before
    public void init() {
        // applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        applicationContext = new AnnotationConfigApplicationContext(BootConfig.class);
    }

在ServiceA,ServiceB,ServiceC類上分別加上@Service注解设凹,setter方法參數(shù)前面加上@Autowired注解舰讹,ServiceA如下:

@Service
public class ServiceA {
    private ServiceB serviceB;

    public void setServiceB(@Autowired ServiceB serviceB) {
        this.serviceB = serviceB;
    }

    public String doSth(){
        System.out.println("serviceA doSth");
        // throw new RuntimeException("an exception ");
        return "hello";
    }
}

啟動測試方法,執(zhí)行結果如下:

serviceA doSth
ServiceB doSth

Bean注解

  • @Component 聲明當前Class為一個ioc bean,Spring掃包的時候會將其作為一個需要管理的bean來解析并實例化
  • @Service
  • @Controller
  • @Repository
    本質上后面三個注解與@Component一樣的效果闪朱,只不過為了區(qū)分代碼層級月匣,提供了后面三個注解。
  • @Autowired 表明某個屬性需要ioc容器來注入奋姿,spring通過類型來找到需要注入的bean, 同時可以通過@Qualifier("beanName")來通過名稱注入锄开。

用AOP注解改造LogUtil.java

package com.test.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

@Aspect
@Component
public class LogUtil {
    @Pointcut("execution(public * com.test.service.ServiceA.doSth())")
    public void pointCut() {
    }

    /**
     * 前面打印
     */
    @Before("com.test.aop.LogUtil.pointCut()")
    public void printBefore() {
        System.out.println("print info from LogUtil.printBefore");
    }

    /**
     * 后面打印
     */
    @After("com.test.aop.LogUtil.pointCut()")
    public void printAfter() {
        System.out.println("print info from LogUtil.printAfter");
    }

    /**
     * 后面打印
     */
    @After("com.test.aop.LogUtil.pointCut()")
    public void printAfterReturning() {
        System.out.println("print info from LogUtil.printAfterReturning");
    }

    /**
     * 后面打印
     */
    @AfterThrowing("com.test.aop.LogUtil.pointCut()")
    public void afterThrowing() {
        System.out.println("print info from LogUtil.afterThrowing");
    }

    @Around("com.test.aop.LogUtil.pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("---around before----");
        Object result = joinPoint.proceed();
        System.out.println(result);
        System.out.println("---around after----");
        return result;
    }
}

改造SpringConfig.java

/**
 * @author felix 
 */
@Configuration
@ComponentScan(basePackages = "com.test")
@EnableAspectJAutoProxy
public class BootConfig {
}

啟動測試,結果如下:

---around before----
print info from LogUtil.printBefore
serviceA doSth
print info from LogUtil.printAfterReturning
print info from LogUtil.printAfter
hello
---around after----
ServiceB doSth

AOP注解開發(fā)称诗,需要@EnableAspectJAutoProxy開啟
用@Aspec生命切面類萍悴,@PointCut定義一個切入點,@Before,@After,@AfterThrowing,@After,@Around分別定義切入時機

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末寓免,一起剝皮案震驚了整個濱河市癣诱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌再榄,老刑警劉巖狡刘,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異困鸥,居然都是意外死亡嗅蔬,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門疾就,熙熙樓的掌柜王于貴愁眉苦臉地迎上來澜术,“玉大人,你說我怎么就攤上這事猬腰∧穹希” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵姑荷,是天一觀的道長盒延。 經常有香客問我,道長鼠冕,這世上最難降的妖魔是什么添寺? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮懈费,結果婚禮上计露,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好票罐,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布叉趣。 她就那樣靜靜地躺著,像睡著了一般该押。 火紅的嫁衣襯著肌膚如雪疗杉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天蚕礼,我揣著相機與錄音乡数,去河邊找鬼。 笑死闻牡,一個胖子當著我的面吹牛,可吹牛的內容都是我干的绳矩。 我是一名探鬼主播罩润,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼翼馆!你這毒婦竟也來了割以?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤应媚,失蹤者是張志新(化名)和其女友劉穎严沥,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體中姜,經...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡消玄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了丢胚。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片翩瓜。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖携龟,靈堂內的尸體忽然破棺而出兔跌,到底是詐尸還是另有隱情,我是刑警寧澤峡蟋,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布坟桅,位于F島的核電站,受9級特大地震影響蕊蝗,放射性物質發(fā)生泄漏仅乓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一匿又、第九天 我趴在偏房一處隱蔽的房頂上張望方灾。 院中可真熱鬧,春花似錦、人聲如沸裕偿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嘿棘。三九已至劲腿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鸟妙,已是汗流浹背焦人。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留重父,地道東北人花椭。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像房午,于是被迫代替她去往敵國和親矿辽。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內容