1. 程式人生 > 實用技巧 >初識Spring專案

初識Spring專案

快速起步

1. 下載依賴包

  1. spring-beans-5.2.2.RELEASE.jar:包含管理Bean和配置檔案的基本功能
  2. spring-core-5.2.2.RELEASE.jar:spring核心包
  3. spring-context-5.2.2.RELEASE.jar:核心擴充套件包,包含大量工具類
  4. spring-expression-5.2.2.RELEASE.jar:表示式解析語言,支援動態的解析表示式給物件賦值等功能
  5. commons-logging-1.2.jar:日誌支援包
  6. log4j-1.2.17.jar:日誌支援包

2. 建立Spring專案

  1. 建立Web專案
  2. 將下載好的JAR檔案複製到WebRoot/WEB-INF/lib
    目錄下
  3. 建立resources資源目錄,並將 log4j.properties 配置檔案拷貝其中
  4. 建立 test 測試目錄

3. 建立JavaBean

建立 beans.HelloSpring

package beans;

public class HelloSpring {
    private String who = null;
    public String getWho() {return who;}
    public void setWho(String who) {this.who = who;}

    public void print(){
        System.out.println("Hello, " + this.getWho() +" ! ");
    }
}

4. 建立核心配置檔案

resources原始碼目錄中建立核心配置檔案applicationContext.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-3.2.xsd">

    <!-- 通過bean元素宣告需要Spring建立的例項。該例項的型別通過class屬性指定,並通過id屬性為該例項指定一個名稱,以便在程式中使用 -->
    <bean id="helloSpring" class="beans.HelloSpring">
        <!-- property元素用來為例項的屬性賦值,此處實際是呼叫setWho()方法實現賦值操作 -->
        <property name="who">
            <!-- 此處將字串"Spring"賦值給who屬性 -->
            <value>Spring</value>
        </property>
    </bean>
</beans>

5. 編寫測試類

test 目錄中,建立單元測試類test.SpringTest

package test;

import beans.HelloSpring;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTest {
    @Test
    public void test() {
        // 例項化Spring的上下文
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 獲取bean的例項
        HelloSpring helloSpring = (HelloSpring) context.getBean("helloSpring");
        // 執行print()方法
        helloSpring.print();
    }
}

Ioc依賴注入

配置檔案實現

注入字面量

value標籤

<bean id="helloSpring" class="beans.HelloSpring">
    <property name="who">
        <value>Spring</value>
    </property>
</bean>

value屬性

<bean id="helloSpring" class="beans.HelloSpring">
    <property name="who" value="value" />
</bean>

P名稱空間

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

 <bean id="helloSpring" class="beans.HelloSpring" p:who="Spring"/>

</beans>

注入物件

內部bean

<bean id="a" class="beans.A">
    <property name="b">
        <bean class="beans.B">
            <property name="str" value="val"></property>
        </bean>
    </property>
</bean>

ref屬性

<bean id="b" class="beans.B">
    <property name="str" value="val"></property>
</bean>
<bean id="a" class="beans.A">
    <property name="b" ref="b"></property>
</bean>

ref標籤

<bean id="b" class="beans.B">
    <property name="str" value="val"></property>
</bean>
<bean id="a" class="beans.A">
    <property name="b">
        <ref bean="b"/>
    </property>
</bean>

P名稱空間

<beans xmlns:p="http://www.springframework.org/schema/p" ...>
    <bean id="b" class="beans.B" p:str="val"/>
    <bean id="a" class="beans.A" p:b-ref="b"/>
</beans>

構造注入

構造方法

public A(String strAttr,int intAttr,B b){
  // ...
}

引數索引

<bean id="b" class="beans.B" p:str="val"/>
<bean id="printer" class="beans.Printer">
    <constructor-arg index="0" value="strValue"/>
    <constructor-arg index="1" value="10"/>
    <constructor-arg index="2" ref="b"/>
</bean>

引數名稱

<bean id="b" class="beans.B" p:str="val"/>
<bean id="printer" class="beans.Printer">
    <constructor-arg name="strAttr" value="strValue"/>
    <constructor-arg name="intAttr" value="10"/>
    <constructor-arg name="b" ref="b"/>
</bean>

注入null值

<bean id="id" class="package.class">
    <property name="attr"><null></null></property>
</bean>

注入空字串

<bean id="id" class="package.class">
    <property name="attr"><value></value></property>
</bean>

注入包含特殊字元的值

CDATA

<bean id="id" class="package.class">
    <property name="attr"><value><![CDATA[P&G]]></value></property>
</bean>

實體符號

<bean id="printer" class="beans.Printer">
    <property name="ink"><value>P&amp;G</value></property>
</bean>

注入List集合

<bean id="id" class="package.class">
    <property name="lists">
        <list>
            <value>黑色</value>
            <value>彩色</value>
        </list>
    </property>
</bean>

注入Set集合

<bean id="id" class="package.class">
    <property name="sets">
        <set>
            <value>黑色</value>
            <value>彩色</value>
        </set>
    </property>
</bean>

注入Map集合

<bean id="id" class="package.class">
    <property name="maps">
        <map>
            <entry>
                <key><value>k1</value></key>
                <value>v1</value>
            </entry>
            <entry>
                <key><value>k2</value></key>
                <value>v2</value>
            </entry>
        </map>
    </property>
</bean>

注入Properties集合

<bean id="id" class="package.class">
    <property name="prop">
        <props>
            <prop key="k1">v1</prop>
            <prop key="k2">v2</prop>
        </props>
    </property>
</bean>

註解實現Ioc

全域性配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-2.0.xsd">
    <!-- 掃描包中註解標註的類 -->
   <context:component-scan base-package="beans"/>
</beans>

定義Bean

定義普通Bean

@Component
public class BeanName { /* ... */ }
// 等效於
@Component("beanName")
public class BeanName { /* ... */ }

定義DAO Bean

@Repository
public class BeanDao { /* ... */ }
// 等效於
@Repository("beanDao")
public class BeanDao { /* ... */ }

定義業務Bean

@Service
public class BeanService { /* ... */ }
// 等效於
@Service("beanService")
public class BeanService { /* ... */ }

定義控制器Bean

@Controller
public class BeanController { /* ... */ }
// 等效於
@Controller("beanController")
public class BeanController { /* ... */ }

裝配Bean

以型別裝配

@Autowired
private BeanClass bean;

如果有多個型別相同的Bean,則需要指定Bean名稱

@Autowired
@Qualifier("beanName")
private BeanClass bean;
// 或
private BeanClass bean;
@Autowired
@Qualifier("beanName")
public void setBean(BeanClass bean) { /* ... */ }
// 或
private BeanClass bean;
@Autowired
public void setBean(@Qualifier("beanName")BeanClass bean) { /* ... */ }

構造方法裝配

@Autowired
public Printer(BeanClass bean){/* ... */}
// 或
@Autowired
public Printer(@Qualifier("beanName")BeanClass bean){/* ... */}

阻止Bean元件不存在時報異常

@Autowired(required = false)
private BeanClass bean;

將相同型別的Bean裝配到集合

@Autowired
private List<BeanClass> beans;

優先以名稱裝配,如果沒有找到指定的Bean,則以型別裝配

// 先找名稱為 bean 的 Bean,如果沒有找,則找名稱為 beanClass 的 Bean,如果還沒有找到,則尋找型別為 BeanClass 的 Bean
@Resource
private BeanClass bean;
// 找名稱為 beanName 的 Bean
@Resource(name="beanName")
private BeanClass bean;
// 找名稱為 bean 的 Bean
private BeanClass bean;
@Resource
public void setBean(BeanClass bean) { /* ... */ }

AOP實現

配置檔案實現

1. 下載依賴包

  1. aopalliance-1.0.jar
  2. aspectjweaver-1.6.9.jar
  3. spring-aop-5.2.2.RELEASE.jar

2. 建立被增強類

package aopdemo;
import org.springframework.stereotype.Component;
@Component("a")
public class A {
    public void fun1() { /* ... */ }
    public void fun2() { throw new RuntimeException("fun2 丟擲異常"); }
    public void fun3() { /* ... */ }
    public void fun4() { throw new RuntimeException("fun4 丟擲異常"); }
}

3. 建立切面

package aopdemo;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;
@Component
public class AspectImpl {
    /**
     * 前置增強
     * @param joinPoint 切入點物件
     */
    public void before(JoinPoint joinPoint) {
        System.err.println("正在執行前置增強。。。");
    }
    /**
     * 後置增強
     * @param joinPoint 切入點物件
     * @param result 被增強方法的返回值
     */
    public void afterReturning(JoinPoint joinPoint, Object result) {
        System.err.println("正在執行後置增強,返回值為:" + result);
    }
    /**
     * 異常增強
     * @param joinPoint 切入點物件
     * @param e 被增強方法丟擲的異常物件
     */
    public void afterThrowing(JoinPoint joinPoint, RuntimeException e) {
        System.err.println("正在執行異常增強,異常為:" + e);
    }
    /**
     * 最終增強
     * @param joinPoint 切入點物件
     */
    public void after(JoinPoint joinPoint) {
        System.err.println("正在執行最終增強。。。");
    }
    /**
     * 環繞增強
     * @param joinPoint 切入點物件
     * @return 被增強方法的返回值
     */
    public Object around(ProceedingJoinPoint joinPoint) {
        Object result = null;
        try {
            System.err.println("開始執行環繞增強。。。");
            result = joinPoint.proceed();
            System.err.println("結束執行環繞增強。。。");
        } catch (Throwable e) {
            System.err.println("環繞增強的異常處理:" + e);
        } finally {
            return result;
        }
    }
}

4. 全域性配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       http://www.springframework.org/schema/aop 
       http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context-3.2.xsd">
    <context:component-scan base-package="aopdemo" />
    <aop:config>
        <!-- 切入點 -->
        <aop:pointcut expression="execution(public void fun1())" id="fun1"/>
        <aop:pointcut expression="execution(public void fun2())" id="fun2"/>
        <aop:pointcut expression="execution(public void fun3())" id="fun3"/>
        <aop:pointcut expression="execution(public void fun4())" id="fun4"/>
        <!-- 切面 -->
        <aop:aspect ref="aspectImpl">
            <!-- 前置增強 -->
            <aop:before method="before" pointcut-ref="fun1" />
            <!-- 後置增強 -->
            <aop:after-returning method="afterReturning" pointcut-ref="fun1" returning="result"/>
            <!-- 異常增強 -->
            <aop:after-throwing method="afterThrowing" pointcut-ref="fun2" throwing="e"/>
            <!-- 最終增強 -->
            <aop:after method="after" pointcut-ref="fun3"/>
            <!-- 環繞增強 -->
            <aop:around method="around" pointcut-ref="fun4"/>
        </aop:aspect>
    </aop:config>
</beans>

5. 編寫測試類

@Test
public void test() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    A a = (A)context.getBean("a");
    // 依次執行一下方法進行測試
    // a.fun1();
    // a.fun2();
    // a.fun3();
    a.fun4();
}

註解實現AOP

切面實現類

package aopdemo;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AspectImpl {
    // 定義通用切入點
    @Pointcut("execution(public void fun1())")
    public void pointcut1() {}
    // 前置增強
    @Before("pointcut1()")
    public void before(JoinPoint joinPoint) { /* ... */ }
    // 後置增強
    @AfterReturning(pointcut = "pointcut1()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) { /* ... */ }
    // 異常增強
    @AfterThrowing(pointcut = "execution(public void fun2())", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, RuntimeException e) { /* ... */ }
    // 最終增強
    @After("execution(public void fun3())")
    public void after(JoinPoint joinPoint) { /* ... */ }
    // 環繞增強
    @Around("execution(public void fun4())")
    public Object around(ProceedingJoinPoint joinPoint) { /* ... */ }
}

全域性配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       http://www.springframework.org/schema/aop 
       http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context-3.2.xsd">
    <context:component-scan base-package="aopdemo" />
     <!-- 啟用Aspectj,並自動建立代理 -->
    <aop:aspectj-autoproxy/>
</beans>

切入點表示式匹配規則

匹配所有型別的返回值

public * addNewUser(entity.User)

匹配所有方法名

public void *(entity.User)

匹配所有引數個數和型別

public void addNewUser(..)

匹配 com.service 包下所有類的所有方法

* com.service.*.*(..)

匹配 com.service 包及其子包下所有類的所有方法

* com.service..*.*(..)

JoinPoint

獲取目標類完全限定名

joinPoint.getTarget()

獲取目標方法名

joinPoint.getSignature().getName()

獲取目標方法入引數組

joinPoint.getArgs()

ProceedingJoinPoint

獲取目標類完全限定名

joinPoint.getTarget()

獲取目標方法名

joinPoint.getSignature().getName()

獲取目標方法入引數組

joinPoint.getArgs()

執行目標方法並獲取返回值

joinPoint.proceed()