SSM框架-Spring


Spring


1. Spring概述

????Spring是應用full-stack輕量級框架,以IoC(Inverse Of Control : 控制反轉(zhuǎn))和AOP(Aspect Oriented Programming : 面向切面編程)為內(nèi)核,提供了表現(xiàn)層SpringMVC和持久層Spring JDBC以及業(yè)務層事務管理等眾多的企業(yè)級應用技術,還能整合開源世界中眾多的第三方框架和類庫。

2. Spring的優(yōu)勢

  1. 方便解耦,簡化開發(fā)
    • 通過Spring提供的IoC容器,可以將對象間的依賴關系交由Spring進行控制,編碼硬編碼所造成的過度程序耦合。
  2. AOP編程支持
    • 通過Spring的AOP功能,方便進行面向切面編程,許多不容易用傳榮OOP實現(xiàn)的功能可以通過AOP輕松實現(xiàn)。
  3. 聲明式事務的支持
    • 可以簡化在事務管理方面的代碼,通過聲明的方式進行靈活的事務管理,提高開發(fā)效率和質(zhì)量
  4. 方便程序的測試
    • 可以用非容器依賴的編程方式進行幾乎所有的測試工作,測試的難度被降低了。
  5. 方便集成各種優(yōu)秀框架
    • Spring提供了對各種郵箱框架的直接支持。
  6. 降低JavaEE API的使用難度
    • Spring對JavaEE API中的代碼(JDBC、JavaMail、遠程調(diào)用等)進行了封裝,降低了使用API的難度。

3. Spring的IoC應用

1. 在Maven中導入Spring的坐標

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
    </dependencies>

2. Spring的主配置文件:applicationContext.xml

  1. 主配置的約束頭信息
<?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">

</beans>
  1. 簡單的Spring配置文件
<!-- 配置service 
        id : 唯一標識
        class : 指定類的全類名
-->
<bean id="accountService" class="com.hsh.study.service.impl.AccountServiceImpl"></bean>

<!-- 配置dao -->
<bean id="accountDao" class="com.hsh.study.dao.impl.AccountDaoImpl"></bean>
  1. 常見屬性標簽
    1. bean標簽:用于配置對象讓Spring來創(chuàng)建。默認情況下Spring調(diào)用類中的無參構造函數(shù),沒有無參構造函數(shù)則不能創(chuàng)建成功
      • 屬性:
        • id:給對象在容器總提供一個唯一標識。用于獲取對象。
        • class:指定類的全限定類名。用于反射創(chuàng)建對象,默認情況下調(diào)用無參構造函數(shù)
        • scope:指定對象的作用范圍。
          1. singleton:默認值,單例對象
          2. prototype:多例的
          3. request:在WEB中,Spring創(chuàng)建一個Bean對象,將對象存入request域中。
          4. session:在WEB中,Spring創(chuàng)建一個Bean對象,將對象存入session域中。
          5. global session:在WEB中,應用在Porlet環(huán)境,如果沒有Porlet環(huán)境那么globalSession相當于Session。
        • init-method:指定類中的初始化方法名稱。
        • destory-method:指定類中銷毀方法的名稱
        • factory-method:指定生產(chǎn)對象的靜態(tài)方法(使用靜態(tài)工廠初始化Bean時)
        • factory-bean:用于指定實例工廠bean的id(使用實例工廠初始化Bean時)
        • factory-method:用于指定實例工廠中創(chuàng)建對象的方法(使用實例工廠初始化Bean時)

3. Spring的執(zhí)行方法

  1. 使用ApplicaionContext接口獲取Spring的容器:ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
  2. 根據(jù)配置文件獲取對象:AccountService accountService = ac.getBean("accountService",AccountService.class);
  3. 使用對象:accountService.saveAccount();

ApplicationContext和BeanFactory的區(qū)別:

  1. BeanFactory是Spring容器中的頂層接口。
  2. ApplicationContext是BeanFactory的子接口。
  3. BeanFactory和ApplicationContext創(chuàng)建對象的時間點不同;
    • BeanFactory:什么時候使用什么時候創(chuàng)建對象
    • ApplicationContext:只要讀取完配置文件,默認情況下就會創(chuàng)建對象。

4. Spring的依賴注入

  1. 依賴注入概念:在編寫程序時,通過IoC(控制反轉(zhuǎn))將對象的創(chuàng)建交給了Spring,但是代碼中不可能出現(xiàn)沒有依賴的情況。IoC解耦只是降低了代碼間的依賴關系,但不會完全消除。
  2. 構造函數(shù)的注入(通過類中的構造函數(shù)給成員變量完成賦值的操作)
    1. 編寫需要進行賦值的實體類
    public class User {
        private String username;
        private Integer age;
        private Date birthday;
    
        public User(String username, Integer age, Date birthday) {
            this.username = username;
            this.age = age;
            this.birthday = birthday;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "username='" + username + '\'' +
                    ", age=" + age +
                    ", birthday=" + birthday +
                    '}';
        }
    }
    
    
    1. 用配置文件通過構造函數(shù)對屬性進行賦值
    <!-- 通過構造器進行屬性注入 -->
    <bean id="user" class="com.hsh.study.domain.User">
        <!-- 通過<constructor-arg>標簽對構造函數(shù)中的屬性進行賦值
                index:指定參數(shù)在構造函數(shù)參數(shù)列表的索引位置
                type:指定參數(shù)在構造函數(shù)中的數(shù)據(jù)類型
                name:指定參數(shù)在構造函數(shù)中的名稱
                ==--- 上面用于指定給誰賦值,下面指定賦什么值 ---==
                value:能賦值的類型為基本數(shù)據(jù)類型和String類型
                ref:能賦值的類型是其他bean類型,必須通過配置文件配置bean
        -->
        <constructor-arg name="username" value="張三"></constructor-arg>
        <constructor-arg name="age" value="18"></constructor-arg>
        <constructor-arg name="birthday" ref="now"></constructor-arg>
    </bean>
    
    <!-- 引入日期 -->
    <bean id="now" class="java.util.Date"></bean>
    
  3. set方法的注入(常用)
    1. 編寫需要進行賦值的實體類
    public class User {
       private String username;
       private Integer age;
       private Date birthday;
       
       public String getUsername() {
           return username;
       }
    
       public void setUsername(String username) {
           this.username = username;
       }
    
       public Integer getAge() {
           return age;
       }
    
       public void setAge(Integer age) {
           this.age = age;
       }
    
       public Date getBirthday() {
           return birthday;
       }
    
       public void setBirthday(Date birthday) {
           this.birthday = birthday;
       }
       @Override
       public String toString() {
           return "User{" +
                   "username='" + username + '\'' +
                   ", age=" + age +
                   ", birthday=" + birthday +
                   '}';
       }
    }
    
    
    1. 用配置文件通過構造函數(shù)對屬性進行賦值
     <!-- 通過set方法注入 -->
    <bean id="user" class="com.hsh.study.domain.User">
        <!-- 通過<property>標簽對屬性進行賦值
                name:找類中set方法后面的部分
                ref:給屬性賦值是其他bean類型
                value:給屬性賦值的是基本數(shù)據(jù)類型或者string類型
         -->
        <property name="username" value="李四"></property>
        <property name="age" value="16"></property>
        <property name="birthday" ref="now"></property>
    </bean>
    
    <!-- 引入日期 -->
    <bean id="now" class="java.util.Date"></bean>
    
  4. 使用p名稱空間注入(本質(zhì)還是調(diào)用set方法)
    1. 編寫需要進行賦值的實體類
    public class User {
       private String username;
       private Integer age;
       private Date birthday;
       
       public String getUsername() {
           return username;
       }
    
       public void setUsername(String username) {
           this.username = username;
       }
    
       public Integer getAge() {
           return age;
       }
    
       public void setAge(Integer age) {
           this.age = age;
       }
    
       public Date getBirthday() {
           return birthday;
       }
    
       public void setBirthday(Date birthday) {
           this.birthday = birthday;
       }
       @Override
       public String toString() {
           return "User{" +
                   "username='" + username + '\'' +
                   ", age=" + age +
                   ", birthday=" + birthday +
                   '}';
       }
    }
    
    
    1. 用配置文件通過構造函數(shù)對屬性進行賦值
    <!-- 導入p標簽的約束文件 -->
    xmlns:p="http://www.springframework.org/schema/p"
    <!-- 通過p標簽進行注入 -->
    <bean id="user" class="com.hsh.study.domain.User"
          p:username="王五" p:age="18" p:birthday-ref="now"
    ></bean>
    
    <!-- 引入日期 -->
    <bean id="now" class="java.util.Date"
    ></bean>
    
  5. 注入集合屬性
    1. 編寫需要進行賦值的實體類
    public class Collection {
        private String[] myStrs;
        private List<String> myList;
        private Set<String> mySet;
        private Map<String,String> myMap;
        private Properties myProps;
    
        public void setMyStrs(String[] myStrs) {
            this.myStrs = myStrs;
        }
    
        public void setMyList(List<String> myList) {
            this.myList = myList;
        }
    
        public void setMySet(Set<String> mySet) {
            this.mySet = mySet;
        }
    
        public void setMyMap(Map<String, String> myMap) {
            this.myMap = myMap;
        }
    
        public void setMyProps(Properties myProps) {
            this.myProps = myProps;
        }
    
        public String[] getMyStrs() {
            return myStrs;
        }
    
        public List<String> getMyList() {
            return myList;
        }
    
        public Set<String> getMySet() {
            return mySet;
        }
    
        public Map<String, String> getMyMap() {
            return myMap;
        }
    
        public Properties getMyProps() {
            return myProps;
        }
    }
    
    1. 用配置文件通過構造函數(shù)對屬性進行賦值
    <!-- 集合的注入 -->
    <bean id="collection" class="com.hsh.study.domain.Collection">
        <!-- 注入集合數(shù)據(jù)
                List結(jié)構:array、List、Set
                Map結(jié)構:map、properties、entry
         -->
        <!-- 數(shù)組注入 -->
        <property name="myStrs">
            <list>
                <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </list>
        </property>
        <!-- list集合注入 -->
        <property name="myList">
            <array>
                <value>AAA</value>
                <value>CCC</value>
                <value>BBB</value>
            </array>
        </property>
        <!-- set集合注入 -->
        <property name="mySet">
            <set>
                <value>BBB</value>
                <value>AAA</value>
                <value>CCC</value>
            </set>
        </property>
        <!-- map集合注入 -->
        <property name="myMap">
            <map>
                <entry key="111" value="AAA"></entry>
                <entry key="222" value="BBB"></entry>
                <entry key="333" value="CCC"></entry>
            </map>
        </property>
        <!-- Props注入 -->
        <property name="myProps">
            <props>
                <prop key="333">AAA</prop>
                <prop key="222">CCC</prop>
                <prop key="111">BBB</prop>
            </props>
        </property>
    </bean>
    

5. Spring基于注解的使用

  1. 在Maven中導入Spring的坐標
  2. 配置Spring的配置文件使得支持注解
    1. 配置文件約束信息中引入注解的約束
    <?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.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
            
    </bean>
    
    1. 在配置文件中開啟對注解的支持
    <?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.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
        <!-- 告知spring創(chuàng)建容器時要掃描的包 -->
        <context:component-scan base-package="com.hsh.study"></context:component-scan>
    </beans>
    
  3. Spring的常用注解
    • 創(chuàng)建對象的:<bean id="" class="" ></bean>
      1. @Component()
        • 將資源交由Spring進行管理,相當于在xml中配置<bean>標簽
        • 默認屬性為value,value即是hean的id,如果不指定value屬性則默認id為當前類名,首字母小寫
      2. @Controller @Service @Repository
        • 這三個注釋的作用與@Component的作用一致,只不過提供了更加明確的語義化
          • @Controller:一般用于表現(xiàn)層
          • @Service:一般用于業(yè)務層
          • @Repository:一般用于持久層
    • 用于注入數(shù)據(jù)的:<property name="" ref="" /> <property name="" value="" />
      1. @Autowired
        • 自動按照類型注入。當使用注解注入屬性時,可以不用聲明set方法。只能注入其他bean類型。當有多個類型匹配時,使用要注入的對象變量名稱作為bean的id。
      2. @Qualifier
        • 在自動按照類型的基礎上,再按照Bean的id注入。在給字段注入時不能獨立使用,必須和@Autowired一起使用;但是給方法參數(shù)注入時可以獨立使用。
        • value:指定bean的id
      3. @Resource
        • 直接按照Bean的id進行注入。也是只能注入其他Bean類型
        • name:指定bean的id
      4. @Value
        • 注入基本數(shù)據(jù)類型和String類型的數(shù)據(jù)
        • value:用于指定值
    • 用于改變作用范圍的:<bean id="" class="" ==scope=""==> </bean>
      1. @Scope
        • 指定bean的作用范圍
        • value:指定范圍的值(==singleton==、==prototype==、request、session、globalsession)
    • 和生命周期相關的:<bean id="" class="" ==init-method=""== ==destory-method=""== />
      1. @PostConstruct
        • 用于指定初始化方法
      2. @PreDestroy
        • 用于指定銷毀方法
    • 用于純注解配置的注解
      1. @Configuration
        • 作用:用于指定當前類是一個spring的配置類,當創(chuàng)建容器時會從該類上加載注解。獲取容器時需要使用AnnotationApplicationContext(有@Configuration注解的類.class)
        • value:用于指定配置類的字節(jié)碼
        • 注:當配置類作為AnnotationConfigApplicationContext對象創(chuàng)建的參數(shù)時,該注解可以不寫。
      2. @ComponentScan
        • 作用:用于指定Spring再初始化容器時要掃描的包。作用和在spring的xml配置文件中的<context:component-scan base-package="com.hsh.study" />的作用相同
        • basePackages:用于指定要掃描的包,和注解中的value屬性作用一致。
      3. @Bean
        • 作用:該注解只能寫在方法上,表明使用此方法創(chuàng)建一個對象并放入Spring的容器中
        • name:給當前的@Bean注解方法創(chuàng)建的對象指定一個名稱
      4. @PropertySource
        • 作用:用于加載.properties文件中的配置。例如當配置數(shù)據(jù)源時,可以把連接數(shù)據(jù)庫的信息寫道properties配置文件中,使用注解指定配置文件的位置。
        • value[]:用于指定properties文件位置。如果是在類路徑下,需要寫上==classpath:==
      5. @Import
        • 作用:用于導入其他配置類,在引入其他配置時可以不用再寫@Configuration注解。
        • value[]:用于指定其他配置類的字節(jié)碼
  4. Spring使用XML和使用注解配置的優(yōu)劣
    1. 使用注解的優(yōu)勢:配置簡單,維護方便,適用于Bean的是實現(xiàn)類由用戶自己開發(fā)
    2. 使用XML的優(yōu)勢:修改時不需要改源碼,不涉及重新編譯和部署。適用于Bean來自第三方,使用其他的Bean。

6. Spring中使用純注解配置

  1. 創(chuàng)建一個主配置類
//@Configuration
@ComponentScan("com.hsh.study")
@Import(JdbcConfig.class)
@PropertySource("classpath:jdbcConfig.properties")
public class SpringConfiguration {

}
  1. 創(chuàng)建JDBC配置類
public class JdbcConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    /**
     * 創(chuàng)建QueryRunner對象
     * @param dataSource
     * @return
     */
    @Bean(name = "runner")
    @Scope("singleton")
    public QueryRunner createQueryRunner(@Qualifier("ds1") DataSource dataSource){
        return new QueryRunner(dataSource);
    }
    /**
     * 創(chuàng)建數(shù)據(jù)庫連接對象
     * @return
     */
    @Bean("ds1")
    public DataSource createDataSource(){
        try{
            ComboPooledDataSource ds = new ComboPooledDataSource();
            ds.setDriverClass(driver);
            ds.setJdbcUrl(url);
            ds.setUser(username);
            ds.setPassword(password);
            return ds;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }
}

  1. 使用注釋完成創(chuàng)建對象和注入
//1. 業(yè)務層
@Service("accountService")
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao accountDao;

    @Override
    public List<Account> findAll() {
        return accountDao.findAll();
    }
}
//2. 持久層
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
    @Autowired
    private QueryRunner runner;

    @Override
    public List<Account> findAll() {
        try {
            return runner.query("select * from account",new BeanListHandler<Account>(Account.class));
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}
  1. 測試
 ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        // 基于注解創(chuàng)建applicationContext
        AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
        List<Account> accounts = accountService.findAll();
        for (Account account1 : accounts){
            System.out.println(account1);
        }

4. Spring整合Junit

1. 導入整合junit的jar包

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>

2. 使用注解@RunWith代替原有運行器

@RunWith(SpringJUnit4ClassRunner.class)
public class JdbcTest2 {
    @Test
    public void test() {
    }
}

3. 使用@ContextConfiguration指定spring配置文件位置

  1. @ContextConfiguration屬性:
    • locations屬性:用于指定配置文件的位置。位于類路徑下需使用classpath:表示。
    • calsses屬性:用于指定注解的類。當不使用xml時,需要用此屬性指定注解類的位置。
  2. 應用
@RunWith(SpringJUnit4ClassRunner.class)
// 使用XML配置文件時
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
// 使用注解時
@ContextConfiguration(classes = {config.SpringConfiguration.class})
public class JdbcTest2 {
    @Test
    public void test() {
    }
}

4. 使用@Autowired給變量注入數(shù)據(jù)

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {config.SpringConfiguration.class})
public class JdbcTest2 {
    @Autowired
    private AccountService accountService;
    @Test
    public void test() {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        accountService = applicationContext.getBean("accountService", AccountService.class);
        List<Account> accounts = accountService.findAll();
        for (Account account1 : accounts){
            System.out.println(account1);
        }
    }
}

5. Spring的AOP

1. 概念:

AOP(Aspect Oriented Programming)面向切面編程。利用AOP對業(yè)務邏輯的各個部分進行隔離,從而降低業(yè)務邏輯各部分之間的耦合度

2. AOP的作用及優(yōu)勢

  1. 作用:在程序運行期間,在不修改源碼的基礎上對已有方法進行增強。
  2. 優(yōu)勢:①減少重復代碼②提高開發(fā)效率③維護方便

3. AOP中相關的術語

  1. JoinPoint(連接點):連接點指的是哪些被攔截到的點。在spring中,這些點指的是方法,因為spring只支持方法類型的連接點。
  2. Pointcut(切入點):切入點指的是對哪些連接點進行攔截的定義。
  3. Advice(通知/增強):通知是指攔截到JoinPoint后所做的事情便是通知。
    • 通知的類型:前置通知,后置通知,異常通知,最終通知和環(huán)繞通知。
  4. Introduction(引介):引介是一種特殊的通知在不修改類代碼的前提下,Introduction可以在運行期間為類動態(tài)的添加一些方法或者Field。
  5. Target(目標對象):代理的目標對象。
  6. Weaving(織入):指把增強應用到目標對象來創(chuàng)建新的代理對象的過程。
  7. Proxy(代理):一個類被AOP織入增強后,就產(chǎn)生了一個結(jié)果代理類。
  8. Aspect(切面):是切入點和通知(引介)的結(jié)合。

3. AOP的使用

  1. 在Maven中引入Spring的AOP坐標
<!-- AOP坐標 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>
  1. 在spring的配置文件中導入約束
    1. spring-AOP的約束頭信息
    <?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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd">
        
    </beans>
    
    1. spring-AOP的配置
      • execution表達式
        1. 在AOP中使用execution表達式首先要導入表達式的坐標
        <!-- AOP使用execution表達式坐標 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.7</version>
        </dependency>
        
        1. execution表達式的使用方法
          • 普通的表達式:權限修飾符 返回值類型 包名.包名...類名.方法名(參數(shù)列表)
          • 標準表達式寫法:public void com.hsh.study.service.impl.AccountServiceImpl.findAll()
          • 權限修飾符可以省略,返回值類型使用通配符代替:* com.hsh.study.service.impl.AccountServiceImpl.findAll()
          • 包名使用通配符代替,幾個類幾個通配符:* *.*.*.*.*.AccountServiceImpl.findAll()
          • 包名可以使用..表示當前包及其子包:* *..AccountServiceImpl.findAll()
          • 方法名和類名都可以使用通配符:* *..*.*()
          • 參數(shù)列表:
            1. 基本數(shù)據(jù)類型直接寫名稱:int
            2. 引用數(shù)據(jù)類型寫包名.類名的方式 java.lang.String
            3. 使用..表示有無參數(shù)均可,有參數(shù)可以為任意類型
          • 全通配寫法:execution(* *..*.*(..))
      • AOP的具體配置
        1. 基本配置
        <!-- 首先導入對應的bean -->
        <bean id="accountService" class="..."></bean>
        <!-- 導入配置方法的bean -->
        <bean id="logger" class="..." ></bean>
        <!-- 配置aop -->
        <aop:config>
            <!-- 配置切入點表達式<aop:pointcut />
                    id:指定表達式唯一標識
                    expression:指定表達式內(nèi)容
                 此標簽寫在<aop:aspect>內(nèi)部表示當前切面可用
                 此標簽寫在<aop:aspect>外部表示所有切面可用
            -->
            <aop:pointcut id="pt1" expression="execution(* *..*.*(..))"/>
        <!-- 配置切面 -->
            <aop:aspect id="logAdvice" ref="transactionManager">
                <!-- 配置前置通知" -->
                <aop:before method="beforePringLog" pointcut-ref="pt1" />
                <!-- 配置后置通知 -->
                <aop:after-returning method="afterReturningPringLog" pointcut-ref="pt1" />
                <!-- 配置異常通知 -->
                <aop:after-throwing method="afterThrowingPringLog" pointcut-ref="pt1" />
                <!-- 配置最終通知 -->
                <aop:after method="afterPringLog" pointcut-ref="pt1" />
                <!-- 配置環(huán)繞通知 -->
                <!-- <aop:around method="aroundPrintLog" pointcut-ref="pt1" />-->
            </aop:aspect>
        </aop:config>
        
        1. 環(huán)繞通知配置
          • 類中
          public Object aroundPrintLog(ProceedingJoinPoint pjp){
          Object resultValue = null;
          try{
              // 得到方法執(zhí)行所需的參數(shù)
              Object[] args = pjp.getArgs();
              // 執(zhí)行前置通知
              System.out.println("前置通知");
              // 執(zhí)行切入點方法
              resultValue = pjp.proceed(args);
              // 執(zhí)行后置通知
              System.out.println("后置通知");
              return resultValue;
          }catch (Throwable e){
              System.out.println("異常通知");
              throw new RuntimeException(e);
          }finally {
              System.out.println("最終通知");
          }
          
        }
        * 配置文件中

        <bean id="accountService" class="..."></bean>

        <bean id="logger" class="..." ></bean>

        <aop:config>

        <aop:pointcut id="pt1" expression="execution(* ...*(..))"/>

        <aop:aspect id="logAdvice" ref="transactionManager">


        </aop:aspect>
        </aop:config>
        ```
  2. 基于注解的Spring-AOP配置
    1. 在配置文件中導入AOP相關的約束頭信息
    <?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.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    </bean>
    
    1. 指定Spring注解所需掃描的包,并開啟對注解AOP的支持
    <!-- 需要掃描的包 -->
    <context:component-scan base-package="com.hsh.study"></context:component-scan>
    <!-- 開啟對注解AOP的支持 -->
    <aop:aspectj-autoproxy/>
    
    1. 針對各實體類進行注解配置
    2. 在通知類中使用注解進行通知
      • 在通知類上使用@Aspect注釋表明這是一個切面類
      @Component("logger")
      @Aspect
      public class Logger {
      
      }
      
      • 切入點表達式注解
        1. @Aspect
          • 作用:指定切入點表達式
          • value:指定表達式的內(nèi)容
      • 針對AOP的四種狀態(tài)對應的注釋
        1. @Before
          • 作用:將當前方法看作前置通知
          • value:用于指定切入點表達式,還可以指定切入點表達式的引用
        2. @After-Returning
          • 作用:將當前方法看作后置通知
          • value:用于指定切入點表達式,還可以指定切入點表達式的引用
        3. @AfterThrowing
          • 作用:將當前方法看作異常通知
          • value:同上
        4. @After
          • 作用:將當前方法看作最終通知
          • value:同上
        5. @Around
          • 作用:將當前方法看作環(huán)繞通知
          • value:同上 @Around("pt1()") //引入切入點時括號要加上
    3. 使用純注解配置時
      • 在配置類上使用注解:@EnableAspectJAutoProxy即可

6. Spring中的JdbcTemplate

1. 概念

JdbcTemplate是Spring框架中提供的一個對象,是對原始JDBC API的簡單封裝。其中提供了許多的操作模板類。

  1. 操作關系數(shù)據(jù)庫:JdbcTemplate、HibernateTemplate
  2. 操作nosql數(shù)據(jù):RedisTemplate
  3. 操作消息隊列:JmsTemplate

2. 基于Spring的JdbcTemplate所必須的jar包或坐標

<!-- JdbcTemplate坐標 -->
 <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>
<!-- 事務控制坐標 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>

3. Spring-JdbcTemplate的使用

1. 編寫Spring的配置文件

  1. 導入spring-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">

</beans>
  1. 配置相應的數(shù)據(jù)源
    <!-- 使用c3p0數(shù)據(jù)庫連接池時 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.cj.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring?useSSL=false" />
        <property name="user" value="root" />
        <property name="password" value="123" />
    </bean>
    <!-- 使用Spring內(nèi)置數(shù)據(jù)源 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driverClass}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>
    <!-- 使用外部配置文件的Spring內(nèi)置數(shù)據(jù)源時 -->
    <!-- 引入外部配置文件 -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:jdbc.properties"></property>
    </bean>
    <!-- 使用注解引入外部文件時 -->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    

2. 使用JdbcTemplate實現(xiàn)增刪改查操作

  1. 在配置文件中配置JdbcTemplate
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource" />
</bean>
  1. 可以直接使用JdbcTemplate實現(xiàn)增刪改查操作

3. 在Dao中使用JdbcTemplate

  1. 不通過繼承JdbcDaoSupport來簡化獲取JdbcTemplate的操作(用于xml配置和注解配置中)
    1. 在Dao實現(xiàn)類中添加jdbcTemplate屬性
    private JdbcTemplate jdbcTemplate;
    
    // 添加注入
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate){
        this.jdbcTemplate = jdbcTemplate;
    }
    
    1. 在配置文件中添加Dao實現(xiàn)類的bean
    <bean id="accountDao" class="...AccountDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate" />
    </bean>
    
    1. 使用jdbcTemplate屬性執(zhí)行數(shù)據(jù)庫操作
  2. 通過繼承JdbcDaoSupport來簡化獲取JdbcTemplate的操作(僅限于xml配置中)
    1. 在Dao實體類中繼承JdbcDaoSupport,不用添加jdbcTemplate屬性
    public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { }
    
    1. 在配置文件中添加Dao實體類的Bean
    <bean id="accountDao" class="..AccountDaoImpl">
        <!-- 可以配置JdbcTemplate也可以配置DataSource 配置一個即可-->
        <!-- 配置JdbcTempldate -->
        <property name="jdbcTemplate" ref="jdbcTemplate" />
        <!-- 配置DataSource -->
        <property name="dataSource" ref="dataSource" />
    </bean>
    
    1. 調(diào)用父類的方法super.getJdbcTemplate()來執(zhí)行相應的數(shù)據(jù)庫操作

7. Spring中的事務控制

  • Spring中關于事務控制的API

1. PlatformTransactionManager(Spring中的事務管理器)

PlatformTransactionManager接口提供了事務操作的方法,其中包含3各具體的操作:

  1. 獲取事務狀態(tài)信息TransactionStatus getTransaction(TransactionDefinition definition)
  2. 提交事務void commit(TransactionStatus status)
  3. 回滾事務void rollback(TransactionStatus status)
    真正使用的是PlatformTransactionManager接口的實體類:
  4. org.springframework.jdbc.datasource.==DataSourceTransactionManager== 使用Spring JDBC或iBatis進行持久化數(shù)據(jù)時使用
  5. org.springframework.orm.hibernate5.==HibernateTransactionManager== 使用Hibernate版本進行持久化數(shù)據(jù)時使用

2. TransactionDefinition

TransactionDefinition是事務的信息定義對象,方法如下:

  1. 獲取事務對象名稱:String getName()
  2. 獲取事務隔離級別:int getIsolationLevel()
    • 默認級別,歸屬以下某一種:ISOLATION_DEFAULT
    • 可以讀取未提交數(shù)據(jù):ISOLATION_READ_UNCOMMITTED
    • 只能讀取已提交數(shù)據(jù),解決臟讀問題(Oracle默認級別):ISOLATION_READ_COMMITTED
    • 是否讀取其他事務提交修改后的數(shù)據(jù),解決不可重復讀問題(MySql默認級別):ISOLATION_REPEATABLE_READ
    • 是否讀取其他事務提交添加后的數(shù)據(jù),解決幻影讀的問題:ISOLATION_SERIALIZABLE
  3. 獲取事務傳播途徑:int getPropagationBehavior()
    • REQUIRED:如果當前沒有事務,就新建一個事務,如果已經(jīng)存在一個事務中,加入到該事務中。(默認值)
    • SUPPORTS:支持當前事務,如果當前沒有事務,就通過非事務方式執(zhí)行
    • MANDATORY:使用當前的事務,如果當前沒有事務則拋異常
    • REQUERS_NEW:新建事務,如果當前在事務中,則將當前事務掛起
    • NOT_SUPPORTED:以非事務的方式執(zhí)行操作,如果當前存在事務,則將當前事務掛起
    • NEVER:以非事務的方式運行,如果當前存在事務,拋出異常
    • NESTED:如果當前存在事務,則在嵌套事務內(nèi)執(zhí)行。如果當前沒有事務,則執(zhí)行REQUIRED類似的操作
  4. 獲取事務超時時間:int getTimeout()
    • 默認值為-1,沒有超時限制。如果有則以秒為單位進行設置
  5. 獲取事務是否只讀:boolean isReadOnly()
    • 只讀事務:查詢
    • 讀寫型事務:增刪改

3. TransactionStatus

TransactionStatus接口提供某個時間點上事務對象的狀態(tài)信息,其中有6個具體的操作

  1. 刷新事務:void flush()
  2. 獲取是否存在存儲點:boolean hasSavepoint()
  3. 獲取事務是否完成:boolean isCompleted()
  4. 獲取事務是否為新的事務:boolean isNewTransaction()
  5. 獲取事務是否回滾:boolean isRollbackOnly()
  6. 設置事務回滾:void setRollbackOnly()
  • Spring中事務控制的具體操作

1. 導入Spring事務控制的相關坐標

<!-- JDBC相關坐標 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>
<!-- 事務控制相關坐標 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>

2. 在配置文件中導入aop和tx約束

<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:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">

</beans>

3. 配置Bean、數(shù)據(jù)源、事務控制、AOP

<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:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">

    <!-- 配置service -->
    <bean id="accountService" class="com.hsh.study.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>

    <!-- 配置DAO -->
    <bean id="accountDao" class="com.hsh.study.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置數(shù)據(jù)源 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.classDriver}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>

    <!-- 配置數(shù)據(jù)庫配置文件 -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:jdbc.properties" />
    </bean>

    <!-- 配置事務管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 導入數(shù)據(jù)源 -->
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- 事務的配置 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager" >
        <!-- 配置事務的屬性 -->
        <tx:attributes>
            <tx:method name="*" read-only="false" propagation="REQUIRED"/>
            <tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
        </tx:attributes>
    </tx:advice>
    <!-- AOP的配置 -->
    <aop:config>
        <!-- 配置切入點表達式 -->
        <aop:pointcut id="pt1" expression="execution(* com.hsh.study.service.impl.*.*(..))"/>
        <!-- 配置AOP -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor>
    </aop:config>
</beans>
  • Spring中事務控制的具體操作(使用注解開發(fā))

  1. 主注解類的配置
// 聲明式配置類
@Configuration
// 告訴Spring要掃描的包
@ComponentScan("com.hsh.study")
// 導入的另一個配置類
@Import(JdbcConfig.class)
// 配置文件的聲明
@PropertySource("classpath:jdbc.properties")
// 開啟注解AOP支持
@EnableAspectJAutoProxy
// 開啟注解事務支持
@EnableTransactionManagement
public class SpringConfig {

}
  1. Jdbc注解類的配置
public class JdbcConfig {
    // @Value:表示引入配置文件中的值
    @Value("${jdbc.classDriver}")
    private String classDriver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    // 聲明jdbcTemplate
    @Bean("jdbcTemplate")
    public JdbcTemplate createJdbcTemplate(DataSource dataSource){
        return new JdbcTemplate(dataSource);
    }
    /**
     * 創(chuàng)建事務管理器
     * Bean注解不配值時,默認類名首字母小寫如DataSourceTransactionManager變成dataSourceTransactionManager
     */
    @Bean
    public DataSourceTransactionManager transactionManager(DataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }
    // 聲明數(shù)據(jù)源
    @Bean("dataSource")
    public DataSource createDataSource(){
        try {
            DriverManagerDataSource manager = new DriverManagerDataSource();
            manager.setDriverClassName(classDriver);
            manager.setUrl(url);
            manager.setUsername(username);
            manager.setPassword(password);
            return manager;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
  1. 業(yè)務層實現(xiàn)
@Service("accountService")
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao accountDao;

    @Override
    @Transactional(readOnly = false,propagation = Propagation.REQUIRED)
    public void transfer(String sourceName, String targetName, Double money) {
        // 獲取兩個用戶
        Account source = accountDao.findByName(sourceName);
        Account target = accountDao.findByName(targetName);
        // 執(zhí)行轉(zhuǎn)賬操作
        source.setMoney(source.getMoney()-money);
        target.setMoney(target.getMoney()+money);
        // 執(zhí)行更新操作
        accountDao.update(source);
        accountDao.update(target);
    }
  1. 持久層實現(xiàn)
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Override
    public Account findById(Integer accountId) {
        List<Account> accounts = jdbcTemplate.query("select * from account where id = ?",
                new BeanPropertyRowMapper<Account>(Account.class), accountId);
        return accounts.isEmpty()?null:accounts.get(0);
    }
    @Override
    public Account findByName(String accountName) {
        List<Account> accounts = jdbcTemplate.query("select * from account where name = ?",
                new BeanPropertyRowMapper<Account>(Account.class), accountName);
        if (accounts.isEmpty()){
            return null;
        }
        if (accounts.size() > 1){
            throw new RuntimeException("結(jié)果集不唯一");
        }
        return accounts.get(0);
    }
    @Override
    public void update(Account account) {
        jdbcTemplate.update("update account set money = ? where id = ?",
                account.getMoney(),account.getId());
    }
}

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容