Spring相关

1.spring概述

1.1.spring的两大核心
  • IOC(Inverse Of Control):反转控制
  • AOP(Aspect Oriented Programming):面向切面编程

2.spring基于XML的IOC环境搭建

2.1.环境搭建
  • spring的pom.xml配置

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.zzx</groupId>
        <artifactId>spring</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>jar</packaging> 
    
        <dependencies>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.6</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.0.2.RELEASE</version>
            </dependency>
        </dependencies>
    </project>
    
  • 在resources目录下新建bean.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">
    	<!--此处是将两个对象放入spring容器中-->
        <bean id="accountService" class="com.zzx.service.impl.AccountServiceImpl"/>
    
        <bean id="accountDao" class="com.zzx.dao.impl.AccountDaoImpl"/>
    </beans>
    
  • 代码测试

    //获取核心容器对象
    ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
    //根据id获取Bean对象
    AccountService as = (AccountService) ac.getBean("accountService");
    //此处的getBean()方法在对象名后面还传入了对象的字节码文件,此时无需再强转了
    AccountDao accountDao = ac.getBean("accountDao", AccountDao.class);
    
2.2.核心容器的两个接口引发出的问题:
  • ApplicationContext: 单例对象适用 采用此接口

    它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象。

  • BeanFactory: 多例对象使用

    它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象。

2.3.spring对bean的管理细节
2.3.1.创建bean的三种方式
  • 使用默认构造函数创建:bean标签内只有id和class属性,没有其他属性和标签时采用的就是默认构造函数,此时如果类中没有默认构造函数,则对象会无法创建

    <bean id="accountService" class="com.zzx.service.impl.AccountServiceImpl"/>
    
  • 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)

    <bean id="instanceFactory" class="com.zzx.factory.InstanceFactory"/>
    <!--下面的factory-bean会找到对应的id的bean标签内的factory工厂,并调用其getAccountService()方法来创建并返回对象,存入spring容器-->
    <bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"/>
    
  • 使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)

    <bean id="accountService" class="com.zzx.factory.StaticFactory" factory-method="getAccountService"/>
    
2.3.2.bean对象的作用范围

bean标签的scope属性,作用是指定bean的作用范围,有如下几个取值:(常用的就是单例和多例)

  • singleton:默认值,表示单例
  • prototype:多例的
  • request:作用于web应用的请求范围
  • session:作用于web应用的会话范围
  • global-session:作用于web应用的集群环境的会话范围,当不是集群环境时,就是session
2.3.3.bean对象的生命周期
  1. 单例对象**(生命周期与容器相同)**

    • 出生:当容器创建时对象就出生了

    • 活着:只要容器还在,对象就一直活着

    • 死亡:容器销毁,对象就死亡了

  2. 多例对象

    • 出生:当我们使用对象时,spring容器才为我们创建该对象
    • 活着:对象只要被使用就一直活着
    • 死亡:当对象长时间不用,而且没有其他的对象引用时,由java的垃圾回收器回收

3.spring中的依赖注入(DI:Dependency Injection)

3.1.DI的概述

​ IOC的作用是降低程序之间的耦合(其实就是降低了程序之间的依赖关系),依赖关系的管理都交由spring来维护。在当前类需要使用到其他类的对象,我们只需要在spring配置文件中说明依赖关系的维护,就称之为依赖注入。

3.2.可以注入的数据
  • 基本类型和String
  • 其他bean类型(在配置文件中或者注解配置过的bean)
  • 复杂类型/集合类型
3.3.注入的方式
3.3.1.使用构造函数注入
  • bean.xml文件的配置
<!--构造函数注入:
	使用的标签:constructor-arg
	标签出现的位置:bean标签的内部
	标签中的属性
		type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
		index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始
		name:用于指定给构造函数中指定名称的参数赋值                        常用的
=============以上三个用于指定给构造函数中哪个参数赋值===============================
value:用于提供基本类型和String类型的数据
ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
    优势:在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。
    弊端:改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。
-->
<bean id="accountService" class="com.zzx.service.impl.AccountServiceImpl">
    <constructor-arg name="name" value="泰斯特"/>
    <constructor-arg name="age" value="18"/>
    <!--此处的birthday是使用ref属性引用了下面定义的bean,ref属性的值与配置的bean的id值一致-->
    <constructor-arg name="birthday" ref="now"/>
</bean>

<!-- 配置一个日期对象 -->
<bean id="now" class="java.util.Date"/>
  • AccountServiceImpl实现类
public class AccountServiceImpl implements AccountService {

    private String name;
    private Integer age;
    private Date birthday;
	  //利用构造方法注入
    public AccountServiceImpl(String name, Integer age, Date birthday) {
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public void saveAccount() {
        System.out.println("service中的saveAccount方法执行了。。。" + name + "," + age + "," + birthday);
    }
}
  • 代码测试
//获取核心容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//根据id获取Bean对象
AccountService as = (AccountService) ac.getBean("accountService");
as.saveAccount();

//输出结果:service中的saveAccount方法执行了。。。泰斯特,18,Tue Dec 17 09:53:19 CST 2019
3.3.2.使用set方法注入
  • bean.xml文件的配置
<!-- set方法注入                更常用的方式
	涉及的标签:property
	出现的位置:bean标签的内部
	标签的属性
		name:用于指定注入时所调用的set方法名称
		value:用于提供基本类型和String类型的数据
		ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
	优势:创建对象时没有明确的限制,可以直接使用默认构造函数
	弊端:如果有某个成员必须有值,则获取对象是有可能set方法没有执行。
    -->
<bean id="accountService" class="com.zzx.service.impl.AccountServiceImpl">
    <!--此处property标签内name属性的值为set方法的名称而不是成员变量的名称-->
    <property name="name" value="TEST" />
    <property name="age" value="21"/>
    <property name="birthday" ref="now"/>
</bean>
  • AccountServiceImpl实现类
public class AccountServiceImpl implements AccountService {
    private String name;
    private Integer age;
    private Date birthday;
	//只需提供set方法
    public void setName(String name) {
        this.name = name;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public void saveAccount() {
        System.out.println("service中的saveAccount方法执行了。。。" + name + "," + age + "," + birthday);
    }
}
  • 代码测试
//获取核心容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//根据id获取Bean对象
AccountService as = (AccountService) ac.getBean("accountService");
as.saveAccount();

//输出结果:service中的saveAccount方法执行了。。。TEST,21,Tue Dec 17 10:12:43 CST 2019
3.3.3.复杂类型的注入
  • bean.xml的配置
<!-- 复杂类型的注入/集合类型的注入
        用于给List结构集合注入的标签:
            list array set
        用于个Map结构集合注入的标签:
            map  props
        结构相同,标签可以互换
-->

<bean id="accountService" class="com.zzx.service.impl.AccountServiceImpl">
	<property name="myStrs">
        <!--此处property内的子标签可以互换-->
		<set>
			<value>AAA</value>
			<value>BBB</value>
			<value>CCC</value>
		</set>
	</property>
   
	<property name="myList">
        <array>
            <value>AAA</value>
            <value>BBB</value>
            <value>CCC</value>
        </array>
    </property>

    <property name="mySet">
        <list>
            <value>AAA</value>
            <value>BBB</value>
            <value>CCC</value>
        </list>
    </property>

    <property name="myMap">
        <props>
            <prop key="testC">ccc</prop>
            <prop key="testD">ddd</prop>
        </props>
    </property>

    <property name="myProps">
        <map>
            <entry key="testA" value="aaa"></entry>
            <entry key="testB">
                <value>BBB</value>
            </entry>
        </map>
    </property>
</bean>
  • AccountServiceImpl实现类
public class AccountServiceImpl implements AccountService {

    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 void saveAccount() {
        System.out.println(Arrays.toString(myStrs));
        System.out.println(myList);
        System.out.println(mySet);
        System.out.println(myMap);
        System.out.println(myProps);
    }
}
  • 代码测试
//获取核心容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//根据id获取Bean对象
AccountService as = (AccountService) ac.getBean("accountService");
as.saveAccount();

/*
输出结果:
[AAA, BBB, CCC]
[AAA, BBB, CCC]
[AAA, BBB, CCC]
{testD=ddd, testC=ccc}
{testA=aaa, testB=BBB}
*/
3.3.4.使用注解注入

4.常用IOC注解

4.1.按照作用分类
  • 使用注解得先在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"
       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在创建容器时要扫描的包,配置所需要的标签不是在beans的约束中,而是一个名称为
	context名称空间和约束中-->
	<context:component-scan base-package="com.zzx"/>
</beans>
  • 曾经XML的配置:
<bean id="accountService" class="com.zzx.service.impl.AccountServiceImpl"
scope=""  init-method="" destroy-method="">
<property name=""  value="" | ref=""/>
</bean>
4.1.1.用于创建对象

他们的作用就和在XML配置文件中编写一个标签实现的功能是一样的

  1. @Component:
  • 作用:用于把当前类对象存入spring容器中

  • 属性value:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。

  1. @Controller:一般用在表现层
  2. @Service:一般用在业务层
  3. @Repository:一般用在持久层

以上三个注解他们的作用和属性与Component是一模一样。

他们三个是spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰

4.1.2.用于注入数据的

他们的作用就和在xml配置文件中的bean标签中写一个标签的作用是一样的

  1. @Autowired:
  • 作用:自动按照类型注入。

只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功

如果ioc容器中没有任何bean的类型和要注入的变量类型匹配,则报错。

如果Ioc容器中有多个类型匹配时:则通过变量名称来匹配要注入哪个对象

  • 出现位置:可以是变量上,也可以是方法上

  • 细节:在使用注解注入时,set方法就不是必须的了。

  1. @Qualifier:(解决使用Autowired注入时,Ioc容器中有多个类型匹配)
  • 作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用。但是在给方法参数注入时可以

  • 属性value:用于指定注入bean的id。

  1. @Resource(相当于Autowired和Qualifier的结合)
  • 作用:直接按照bean的id注入。它可以独立使用

  • 属性name:用于指定bean的id。

以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。

另外,集合类型的注入只能通过XML来实现。

  1. @Value:
  • 作用:用于注入基本类型和String类型的数据

  • 属性:

    value:用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式)

      SpEL的写法:${表达式}
    
4.1.3.用于改变作用范围的

他们的作用就和在bean标签中使用scope属性实现的功能是一样的

@Scope

  • 作用:用于指定bean的作用范围
  • 属性value:指定范围的取值。常用取值:singleton prototype,默认单例
4.1.4.和生命周期相关

他们的作用就和在bean标签中使用init-method和destroy-methode的作用是一样的

@PreDestroy

  • 作用:用于指定销毁方法

@PostConstruct

  • 作用:用于指定初始化方法

5.spring基于xml配置实现单表的crud

  • pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zzx</groupId>
    <artifactId>spring_withoutxml</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

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

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>

        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.4</version>
        </dependency>

        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
</project>
  • bean.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">
    <!-- 配置Service -->
    <bean id="accountService" class="com.zzx.service.impl.AccountServiceImpl">
        <!-- 注入dao -->
        <property name="accountDao" ref="accountDao"/>
    </bean>

    <!--配置Dao对象-->
    <bean id="accountDao" class="com.zzx.dao.impl.AccountDaoImpl">
        <!-- 注入QueryRunner -->
        <property name="runner" ref="runner"/>
    </bean>

    <!--配置QueryRunner-->
    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
        <!--注入数据源-->
        <constructor-arg name="ds" ref="dataSource"/>
    </bean>

    <!-- 配置数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!--连接数据库的必备信息-->
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///zzx"/>
        <property name="user" value="root"/>
        <property name="password" value="123"/>
    </bean>
</beans>

6.spring基于注解实现单表的crud(没有xml)

  • 新增配置类:SpringConfiguration,该类的作用等同于bean.xml
  • 几个新注解:
  1. @Configuration
  • 作用:指定当前类是一个配置类

  • 细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写。

  1. @ComponentScan
  • 作用:用于通过注解指定spring在创建容器时要扫描的包

  • 属性value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包。

    我们使用此注解就等同于在xml中配置了:

<context:component-scan base-package="com.zzx">
  1. @Bean
  • 作用:用于把当前方法的返回值作为bean对象存入spring的ioc容器中
  • 属性name:用于指定bean的id。当不写时,默认值是当前方法的名称

  • 细节:

    当我们使用注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象。

    查找的方式和Autowired注解的作用是一样的

  1. @Import
  • 作用:用于导入其他的配置类
  • 属性value:用于指定其他配置类的字节码。
  • 当我们使用Import的注解之后,有Import注解的类就是父配置类,而导入的都是子配置类
  1. @PropertySource
  • 作用:用于指定properties文件的位置
  • 属性value:指定文件的名称和路径。
  • 关键字:classpath,表示类路径下

SpringConfiguration.class

//@Configuration //说明该类是一个配置类,但该注解不是必须的,当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写
@ComponentScan(basePackages = "com.zzx") //配置扫描的包路径
@Import(JdbcConfig.class) //导入jdbc的子配置类
@PropertySource("classpath:jdbcConfig.properties") //加了classpath关键字以后代表该路径是类路径
public class SpringConfiguration {
}

jdbcConfig.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///zzx
jdbc.username=root
jdbc.password=123

JdbcConfiguration.class

//由于在SpringConfiguration.class中使用了@Import注解,在此处就无需再加@Configuration注解了
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;
    
    @Bean(name = "runner") //将QueryRunner对象创建之后存入spring的ioc容器中
    @Scope("prototype") //说明创建的该对象是多例的
    //此处参数上的注解Qualifer的值为下面配置的dataSource的name属性的值
    public QueryRunner createQueryRunner(@Qualifer("dataSource") DataSource dataSource) {
        return new QueryRunner(dataSource);
    }

    @Bean(name = "dataSource") //连接数据库的配置
    public DataSource createDataSource() {
        try {
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            dataSource.setDriverClass(driver);
            dataSource.setJdbcUrl(url);
            dataSource.setUser(username);
            dataSource.setPassword(password);
            return dataSource;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

测试类:

@Test
public void testFindAll() {
	//ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
    //使用注解时应该使用AnnotationConfigApplicationContext这个对象
	AnnotationConfigApplicationContext context = new  AnnotationConfigApplicationContext(SpringConfiguration.class);
	AccountDao accountDao = context.getBean("accountDao", AccountDao.class);
	List<Account> accounts = accountDao.findAll();
	for (Account account : accounts) {
		System.out.println(account);
	}
}

7.AOP

7.1AOP概述

AOP全称是:Aspect Oriented Programmer ,即面向切面编程

7.2.AOP的作用及优势
  • 作用:在程序运行期间,不修改源码对已有方法进行增强

  • 优势:

    ​ 减少重复代码

    ​ 提高开发效率

    ​ 维护方便

7.3.AOP相关术语
  • Joinpoint(连接点):连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。

  • Pointcut(切入点):切入点指的是我们要对哪些Joinpoint进行拦截的定义,即被增强的方法就是切入

    由此可知:所有的切入点都是连接点,但并不是所有的连接点都是切入点,只有被增强过的连接点才是切入点

  • Advice(通知/增强):拦截到 Joinpoint 之后所要做的事情就是通知。

    通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。

  • Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 Field。(了解)

  • Target(目标对象):代理的目标对象。

  • Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程

    spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。

  • Proxy(代理):一个类被 AOP 织入增强后,就产生一个结果代理类。

  • Aspect(切面):是切入点和通知(引介)的结合

7.4.spring基于xml实现AOP

需要引入Spring和aop的相关依赖

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

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.7</version>
</dependency>

bean.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"
       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">

    <!--spring中基于XML的AOP配置步骤
        1、把通知Bean也交给spring来管理
        2、使用aop:config标签表明开始AOP的配置
        3、使用aop:aspect标签表明配置切面
                id属性:是给切面提供一个唯一标识
                ref属性:是指定通知类bean的Id。
        4、在aop:aspect标签的内部使用对应标签来配置通知的类型
               我们现在示例是让printLog方法在切入点方法执行之前之前:所以是前置通知
               aop:before:表示配置前置通知
                    method属性:用于指定Logger类中哪个方法是前置通知
                    pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强

            切入点表达式的写法:
                关键字:execution(表达式)
                表达式:
                    访问修饰符  返回值  包名.包名.包名...类名.方法名(参数列表)
                标准的表达式写法:
                    public void com.zzx.service.impl.AccountServiceImpl.saveAccount()
                访问修饰符可以省略
                    void com.zzx.service.impl.AccountServiceImpl.saveAccount()
                返回值可以使用通配符,表示任意返回值
                    * com.zzx.service.impl.AccountServiceImpl.saveAccount()
                包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*.
                    * *.*.*.*.AccountServiceImpl.saveAccount())
                包名可以使用..表示当前包及其子包
                    * *..AccountServiceImpl.saveAccount()
                类名和方法名都可以使用*来实现通配
                    * *..*.*()
                参数列表:
                    可以直接写数据类型:
                        基本类型直接写名称           int
                        引用类型写包名.类名的方式   java.lang.String
                    可以使用通配符表示任意类型,但是必须有参数
                    可以使用..表示有无参数均可,有参数可以是任意类型
                全通配写法:
                    * *..*.*(..)

                实际开发中切入点表达式的通常写法:
                    切到业务层实现类下的所有方法
                        * com.zzx.service.impl.*.*(..)
    -->
  
      <!-- 配置srping的Ioc,把service对象配置进来-->
    <bean id="accountService" class="com.zzx.service.impl.AccountServiceImpl"/>

    <!-- 配置Logger类 -->
    <bean id="logger" class="com.zzx.utils.Logger"/>

    <!--配置AOP-->
    <aop:config>
        <!--配置切面 -->
        <aop:aspect id="logAdvice" ref="logger">
            <!-- 配置通知的类型,并且建立通知方法和切入点方法的关联-->
            <aop:before method="printLog" pointcut="execution(* com.zzx.service.impl.*.*(..))"/>
        </aop:aspect>
    </aop:config>
</beans>
7.5.四种常用通知类型
<aop:config>
	<!-- 配置切入点表达式 id属性用于指定表达式的唯一标识。expression属性用于指定表达式内容
		此标签写在aop:aspect标签内部只能当前切面使用。
		它还可以写在aop:aspect外面,此时就变成了所有切面可用
	-->
	<aop:pointcut id="pt1" expression="execution(* com.zzx.service.impl.*.*(..))"/>
        <!--配置切面 -->
	<aop:aspect id="logAdvice" ref="logger">
		<!-- 配置前置通知:在切入点方法执行之前执行
		<aop:before method="beforePrintLog" pointcut-ref="pt1" />-->

		<!-- 配置后置通知:在切入点方法正常执行之后值。它和异常通知永远只能执行一个
		<aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"/>-->

		<!-- 配置异常通知:在切入点方法执行产生异常之后执行。它和后置通知永远只能执行一个
		<aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"/>-->

		<!-- 配置最终通知:无论切入点方法是否正常执行它都会在其后面执行
		<aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>-->

		<!-- 配置环绕通知 详细的注释请看Logger类中-->
		<aop:around method="aroundPringLog" pointcut-ref="pt1"/>
	</aop:aspect>
</aop:config>
7.6.spring基于注解实现AOP
  • bean.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"
       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">

    <!-- 配置spring创建容器时要扫描的包-->
    <context:component-scan base-package="com.zzx"/>

    <!-- 配置spring开启注解AOP的支持 -->
    <aop:aspectj-autoproxy/>
</beans>
  • logger通知类
@Component("logger")
@Aspect//表示当前类是一个切面类
public class Logger {

    @Pointcut("execution(* com.zzx.service.impl.*.*(..))") //切入点表达式
    private void pt1(){}

	//前置通知,注意:引用切入点时一定要加括号,即写成pt1会报错
		@Before("pt1()")
    public  void beforePrintLog(){
        System.out.println("前置通知Logger类中的beforePrintLog方法开始记录日志了。。。");
    }

    //后置通知
		@AfterReturning("pt1()")
    public  void afterReturningPrintLog(){
        System.out.println("后置通知Logger类中的afterReturningPrintLog方法开始记录日志了。。。");
    }
    
    //异常通知
		@AfterThrowing("pt1()")
    public  void afterThrowingPrintLog(){
        System.out.println("异常通知Logger类中的afterThrowingPrintLog方法开始记录日志了。。。");
    }

    //最终通知
		@After("pt1()")
    public  void afterPrintLog(){
        System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志了。。。");
    }
    
    @Around("pt1()")
    public Object aroundPringLog(ProceedingJoinPoint pjp){
        Object rtValue = null;
        try{
            Object[] args = pjp.getArgs();//得到方法执行所需的参数
            System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。前置");
            rtValue = pjp.proceed(args);//明确调用业务层方法(切入点方法)
            System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。后置");
            return rtValue;
        }catch (Throwable t){
            System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。异常");
            throw new RuntimeException(t);
        }finally {
            System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。最终");
        }
    }
}

8.spring基于XML的声明式事务控制

  • bean.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"
       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.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 配置业务层-->
    <bean id="accountService" class="com.zzx.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>

    <!-- 配置账户的持久层-->
    <bean id="accountDao" class="com.zzx.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"/>
    </bean>


    <!-- 配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///zzx"/>
        <property name="username" value="root"/>
        <property name="password" value="123"/>
    </bean>

    <!-- spring中基于XML的声明式事务控制配置步骤
        1、配置事务管理器
        2、配置事务的通知
                此时我们需要导入事务的约束 tx名称空间和约束,同时也需要aop的
                使用tx:advice标签配置事务通知
                    属性:
                        id:给事务通知起一个唯一标识
                        transaction-manager:给事务通知提供一个事务管理器引用
        3、配置AOP中的通用切入点表达式
        4、建立事务通知和切入点表达式的对应关系
        5、配置事务的属性
               是在事务的通知tx:advice标签的内部

     -->
    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 配置事务的通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!-- 配置事务的属性
                isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
                propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
                read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。
                timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
                rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。
                no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。
        -->
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED" read-only="false"/>
            <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
        </tx:attributes>
    </tx:advice>

    <!-- 配置aop-->
    <aop:config>
        <!-- 配置切入点表达式-->
        <aop:pointcut id="pt1" expression="execution(* com.zzx.service.impl.*.*(..))"/>
        <!--建立切入点表达式和事务通知的对应关系 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"/>
    </aop:config>
</beans>

9.spring基于注解的声明式事务控制

bean.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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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/tx
        http://www.springframework.org/schema/tx/spring-tx.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">

    <!-- 配置spring创建容器时要扫描的包-->
    <context:component-scan base-package="com.zzx"/>

    <!-- 配置JdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/eesy"/>
        <property name="username" value="root"/>
        <property name="password" value="1234"/>
    </bean>

    <!-- spring中基于注解 的声明式事务控制配置步骤
        1、配置事务管理器
        2、开启spring对注解事务的支持
        3、在需要事务支持的地方使用@Transactional注解
     -->
    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 开启spring对注解事务的支持-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值