spring4

Spring框架简介

  1. 主要发明者:Rod Johnson
  2. 轮子理论推崇者:
    • 轮子理论:不用重复发明轮子。
    • IT行业:直接使用写好的代码。
  3. Spring框架宗旨:不重新发明技术,让原有技术使用起来更加方便。
  4. Spring的极大核心功能
    • Ioc/DI:控制反转/依赖注入
    • Aop:面向切面编程
    • 声明式事务
  5. Spring框架的runtime
    • test:Spring框架提供的测试功能
    • Core Container容器:核心容器。Spring启动基本的条件
      • Beans:Spring负责创建类对象并管理对象。
      • Core:核心类库。
      • Context:上下文参数,获取外部资源或者管理注解。
      • SpEl:expression.jar
    • AOP:实现aop功能需要依赖
    • Aspects:切面AOP依赖的包
    • Data Access/Integration:spring封装数据访问层相关内容
      • jdbc:spring对jdbc封装后的代码。
      • ORM:封装持久层框架的代码;如Hibernate
    • transaction:对应spring-tx.jar 声明式事务
    • WEB:需要spring完成Web相关功能时需要
      • 例如:由tomcat加载spring配置文件需要有spring-web

1571831446_1_.png

  1. Spring框架中重要概念:
    • 容器(container):spring当做一个大容器
    • BeanFactory接口:老版本。
      • 新版本中ApplicationContext接口BeanFactory子接口。BeanFactory的功能在ApplicationContext中都有。
  2. 从Spring3开始把Spring框架的功能拆分成多个.jar

SpringIoc简介:

  1. 中文名称:控制反转
  2. 英文名称:(Inversion of Control)
  3. Ioc是什么?
    • Ioc完成的事情是原先由程序主动通过new实例化对象事情,转交给Spring负责。
    • 控制反转中的控制指的是:控制类的对象。
    • 控制反转中的反转指的是:转交给Spring负责。
    • Ioc最大的作用:解耦
    • 程序员不需要去管理对象。解除了对象管理和程序员之间的耦合。

Spring环境搭建

  1. 导入jar包

    • 四个核心包+日志包
  2. 在src下新建applicationContext.xml

    • 文件名称和路径自定义
    • 记住Spring容器applicationContext,applicationContext配置的信息最终存储到了applicationContext容器中。
    • Spring配置文件是基于schema
      • Schema文件扩展名.xsd
      • 把Schema理解成Dtd的升级版
        • 比dtd具备更好的扩展性。
      • 每次引入一个xsd配置文件就是一个namespace(xmlns)
      • 配置文件中只需要导入schema即可。
        • 通过</bean>创建对象。
        • 对象是在加载配置文件时被加载。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <?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">
    <!--
    id:表示获取到对象标识
    class:创建哪个类的对象
    -->
    <bean id="peo" class="com.gdaib.pojo.People"></bean>
    </beans>
  3. 编写测试方法

    • getBean(“<bean/>属性的id值”,创建的对象类型)。
    • getBeanDefinitionNames():获取bean属性管理的所有对象。
    1
    2
    3
    4
    5
    6
    7
    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
    People people = ac.getBean("peo",People.class);
    System.out.println(people);
    String[] names = ac.getBeanDefinitionNames();
    for (String string : names) {
    System.out.println(string);
    }

Spring创建对象的三种方式:

  1. 通过构造方法创建

    • 无参构造创建:默认情况
    • 有参构造创建:需要明确配置
      • 需要在类提供有参构造方法
      • applicationContext.xml中设置调用哪个构造方法创建对象。
        • 如果设定的条件匹配多个构造方法,执行最后的构造方法。
        • index:参数的索引,从0开始。
        • name:参数名。
        • type:参数类型。
        • value指定参数的参数值。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <?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">
    <!--
    id:表示获取到对象标识
    class:创建哪个类的对象
    -->
    <bean id="peo" class="com.gdaib.pojo.People">
    <!-- ref引用另一个bean;value基本数据类型或String等 -->
    <!-- <constructor-arg index="0" value="123"></constructor-arg>
    <constructor-arg index="1" value="张三"></constructor-arg> -->

    <constructor-arg index="0" name="id" type="int" value="321"></constructor-arg>
    <constructor-arg index="1" name="name" type="java.lang.String" value="李四"></constructor-arg>
    </bean>
    </beans>
  2. 实例工厂

    • 工厂设计模式:帮助创建类对象,一个工厂可以生产多个对象。
    • 实例工厂:需要先创建工厂,才能生产对象。
    • 实现步骤:
      • 需要有一个实例工厂模式
    1
    2
    3
    4
    5
    6
    7
    package com.gdaib.pojo;

    public class PeopleFactory2 {
    public People newInstance() {
    return new People(1,"测试");
    }
    }
  • 在applicationContext.xml配置并创建bean对象。
1
2
3
<!-- 实例工厂 -->
<bean id="factory" class="com.gdaib.pojo.PeopleFactory2"></bean>
<bean id="peo1" factory-bean="factory" factory-method="newInstance"></bean>
  1. 静态工厂
    • 不需要创建工厂,快速创建对象
    • 实现步骤:
      • 编写一个静态工厂(在方法上加上一个static)
    1
    2
    3
    4
    5
    6
    7
    package com.gdaib.pojo;

    public class PeopleFactory2 {
    public static People newInstance() {
    return new People(1,"测试");
    }
    }
  • 在applicationContext.xml进行配置
1
2
<!-- 静态工厂 -->
<bean id="peo2" class="com.gdaib.pojo.PeopleFactory2" factory-method="newInstance"></bean>

如何给Bean的属性赋值(注入)

  1. 通过构造方法设置值
  2. 设置注入(setter方法)
    • 如果属性是基本数据类型或String类型
    1
    2
    3
    4
    <bean id="peo" class="com.gdaib.pojo.People">
    <property name="id" value="555"></property>
    <property name="name" value="张三"></property>
    </bean>
  • 等效于
1
2
3
4
<bean id="peo" class="com.gdaib.pojo.People">
<property name="id"><value>345</value></property>
<property name="name"><value>lisi</value></property>
</bean>
  • 如果属性是Set<?>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<bean id="peo" class="com.gdaib.pojo.People">
<property name="id">
<value>567</value>
</property>
<property name="name">
<value>lisi</value>
</property>

<property name="sets">
<set>
<value>1</value>
<value>2</value>
<value>3</value>
<value>4</value>
</set>
</property>
</bean>
  • 如果对象是List<?>集合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<bean id="peo" class="com.gdaib.pojo.People">
<property name="id">
<value>567</value>
</property>
<property name="name">
<value>lisi</value>
</property>
<property name="lists">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
<value>4</value>
</list>
</property>
</bean>
  • 如果list集合中只有一个值
1
<property name="list" value="1"></property>
  • 如果属性是数组时
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<bean id="peo" class="com.gdaib.pojo.People">
<property name="id">
<value>567</value>
</property>
<property name="name">
<value>lisi</value>
</property>
<property name="strs">
<array>
<value>1</value>
<value>2</value>
<value>3</value>
<value>4</value>
</array>
</property>
</bean>
  • 如果数组中只有一个值
1
<property name="strs" value="1"></property>
  • 如果属性是map
1
2
3
4
5
6
<property name="maps">
<map>
<entry key="1" value="2"></entry>
<entry key="3" value="4"></entry>
</map>
</property>
  • 如果属性是Properties时
1
2
3
4
5
6
<property name="demo">
<props>
<prop key="key1">value1</prop>
<prop key="key2">value2</prop>
</props>
</property>

DI

  1. DI:中文名称:依赖注入
  2. DI: 英文名称:Dependency Injection
  3. DI是什么?
    • DI和IOC是一样的
    • 当一个类(A)中需要依赖另一个类(B)对象时,把B赋值给A的过程就叫注入。
  4. 代码体现
    1
    2
    3
    4
    5
    6
    7
    8
    <bean id="peo" class="com.gdaib.pojo.People">
    <property name="desk" ref="desk"></property>

    </bean>
    <bean id="desk" class="com.gdaib.pojo.Desk">
    <property name="id" value="1"></property>
    <property name="price" value="12.3"></property>
    </bean>

使用Spring简化Mybatis

  1. 导入jar包:导入Mybatis所有的jar包和spring基本包,spring-jdbc,spring-tx,spring-aop,spring整合mybatis的包等。

spring-mybatis.png

  1. 编写spring配置文件:applicationContext.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    <?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-jdbc.jar
    -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC&amp;characterEncoding=UTF8"></property>
    <property name="username" value="root"></property>
    <property name="password" value="123456"></property>
    </bean>
    <!-- 依赖注入 创建SqlSessionFactory对象-->
    <bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!-- 数据库连接信息来源与DataSource -->
    <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 扫描器 相当Mybatis中Mappers标签下的package标签,扫描com.gdaib.mapper包后会给对应接口创建对象 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!-- 指定要扫描哪个包 -->
    <property name="basePackage" value="com.gdaib.mapper"></property>
    <!-- 和factory产生关系 -->
    <property name="sqlSessionFactory" ref="factory"></property>
    </bean>
    <!-- 由spring来管理实现类 -->
    <bean id="airportService" class="com.gdaib.pojo.impl.AirportServiceImpl">
    <property name="airportMapper" ref="airportMapper"></property>
    </bean>
    </beans>
  2. 编写代码

    • 正常编写pojo
    • 编写Mapper包下时必须使用接口绑定方案或者注解方法(必须有接口)
    • 正常编写Service接口和Service接口的实现类
      • 需要在Service实现类中声明Mapper接口对象,并生成getter和setter方法。
    • spring无法管理Servlet

    AOP

  3. AOP:中文名称:面向切面编程

  4. AOP: 英文名称:Aspect Oriented Programming

  5. 正常程序执行流程都是纵向执行流程。

    • 又叫面向切面编程,在原有纵向执行流程中添加横切面。
    • 不需要修改原有程序代码(体现出程序高扩展性)
      • 高扩展性
      • 原有功能相当于释放了部分逻辑,让职责更加明确。
  6. 面向切面编程是什么?

    • 在程序原有纵向执行流程中,针对某一个某一些方法添加通知,形成横切面的过程就叫做面向切面编程。
  7. 常用概念

    • 原有功能:切点:pointcut
    • 前置通知:在切点之前执行的功能:before advice
    • 后置通知:在切点之后执行的功能:after advice
    • 如果切点执行过程中出现异常,会触发异常通知。throwable advice
    • 所有功能的总称叫做切面
    • 织入:把切面嵌入到原有功能的过程叫做织入。
  8. Spring提供了2中AOP方式

    • Schema-based
      • 每个通知都需要实现接口或类。
      • 配置spring文件时在<aop:config>配置
    • AspectJ
      • 每个通知不需要实现类或接口
      • 配置spring配置文件是在<aop:config>的字标签<aop:aspect>中配置。
    • schema-based实现步骤:
      • 导入jar包

aop.png

  • 新建通知类:前置通知类和后置通知类
  • arg0:切点方法对象 Method对象
  • arg1:切点方法参数
  • arg2:切点在哪个对象中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.gdaib.advise;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class MyBeforeAdvice implements MethodBeforeAdvice{

@Override
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {

System.out.println("前置通知");

}

}
  • arg0:切点方法返回值
  • arg1:切点方法对象
  • arg2:切点方法参数
  • arg4:切点方法所在类的对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.gdaib.advise;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

public class MyAfterAdvice implements AfterReturningAdvice{

@Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
// TODO Auto-generated method stub
System.out.println("执行后置通知");
}
}
  • 配置spring配置文件
    • 引入aop命名空间
    • 配置通知类<bean/>
    • 配置通知 <aop:advisor>
    • *:通配符,匹配任意方法名,任意类名,任意一级包名
    • (..):如果希望匹配任意方法参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<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">
<!-- 配置通知类对象 -->
<bean id="mybefore" class="com.gdaib.advise.MyBeforeAdvice"></bean>
<bean id="myafter" class="com.gdaib.advise.MyAfterAdvice"></bean>
<!-- 添加切面功能 Schema-based-->
<aop:config>
<!-- 配置切点 -->
<aop:pointcut expression="execution(* com.gdaib.test.Demo.demo2())" id="mypoint"/>
<!-- 添加前置通知 -->
<aop:advisor advice-ref="mybefore" pointcut-ref="mypoint"/>
<!-- 添加后置通知 -->
<aop:advisor advice-ref="myafter" pointcut-ref="mypoint"/>

</aop:config>
<!-- 配置demo,测试时使用 -->
<bean id="demo" class="com.gdaib.test.Demo"></bean>
</beans>
  • 测试
1
2
3
4
5
6
7
8
9
10
11
12
public class Demo {
public void demo1() {
System.out.println("demo1");
}
public void demo2() {
System.out.println("demo2");
}
public void demo3() {
System.out.println("demo3");
}

}
1
2
3
4
5
6
7
8
9
10
11
12
public class Test {
public static void main(String[] args) {
//AOP 扩展
//IOC 解耦

ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
Demo demo=ac.getBean("demo",Demo.class);
demo.demo1();
demo.demo2();
demo.demo3();
}
}
  • 运行结果

aop-result.png

配置异常通知的步骤:(AspectJ)

  1. 只有当切点报异常才能出发异常通知.
  2. 在spring中有AspectJ方式提供了异常通知的方法。
    • 如果希望通过Schema-based实现需要按照特定的要求自己编写方法
  3. 实现步骤:
    • 新建一个类,在类中写任意名称的方法
    1
    2
    3
    4
    5
    6

    public class Myexception implements ThrowsAdvice{
    public void myexcetion(Exception e) {
    System.out.println("异常捕获通知:"+e.getMessage());
    }
    }
  • 在spring配置文件中配置
    • <aop:aspect>的ref属性表示:方法在哪个类中
    • <aop:xxx>表示什么通知
    • method:表示调用哪个方法
    • throwing:异常对象名,必须和通知方法中参数名相同(可以不再通知方法中添加任何参数)
1
2
3
4
5
6
7
8
<bean id="my" class="com.gdaib.advise.Myexception"></bean>
<aop:config>
<aop:aspect ref="my">
<aop:pointcut expression="execution(* com.gdaib.test.Demo.demo1())" id="mypoint"/>
<aop:after-throwing method="myexcetion" pointcut-ref="mypoint" throwing="e"/>
</aop:aspect>
</aop:config>
<bean id="demo" class="com.gdaib.test.Demo"></bean>

使用Schema-base方式实现异常通知

  1. 新建一个类实现ThrowAdvice接口

    • 必须自己写方法,且必须叫afterThrowing
    • 有两种参数方式,必须一个或四个
    • throwing值必须和方法参数名一致.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    package com.gdaib.advise;

    import org.springframework.aop.ThrowsAdvice;

    public class MyThrow implements ThrowsAdvice{
    public void afterThrowing(ArithmeticException ex) throws Throwable {
    System.out.println("异常通知Schema-based");
    }

    }
  2. 在spring的applicationContext.xml中进行配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <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">

    <bean id="mythrow" class="com.gdaib.advise.MyThrow"></bean>
    <aop:config>
    <aop:pointcut expression="execution(* com.gdaib.test.Demo.demo1())" id="mypoint"/>
    <aop:advisor advice-ref="mythrow" pointcut-ref="mypoint"/>
    <aop:aspect>
    <aop:after-throwing method="mythrow" throwing="ex"/>
    </aop:aspect>
    </aop:config>
    <bean id="demo" class="com.gdaib.test.Demo"></bean>
    </beans>

环绕通知(schema-base)

  1. 把前置通知和后置通知都写到一个通知中,成为环绕通知。
  2. 实现步骤:
    • 新建一个类实现MethodInterceptor接口,并重写invoke方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    /***
    * 环绕通知(schema-base)
    * @author 1huangzewei
    *
    */
    public class MyArround implements MethodInterceptor{

    @Override
    public Object invoke(MethodInvocation arg0) throws Throwable {
    System.out.println("环绕-前置");
    Object result = arg0.proceed(); //放行,调用切点方式
    System.out.println("环绕-后置");
    return result;
    }
    }
  • 在spring中配置applicationContext.xml文件
1
2
3
4
5
6
<bean id="myarround" class="com.gdaib.advise.MyArround"></bean>
<aop:config>
<aop:pointcut expression="execution(* com.gdaib.test.Demo.demo1())" id="mypoint"/>
<aop:advisor advice-ref="myarround" pointcut-ref="mypoint"/>
</aop:config>
<bean id="demo" class="com.gdaib.test.Demo"></bean>

ApsectJ方式实现

  1. 新建类,不用实现任何方法

    • 类中的方法任意定义
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class MyAdvice {
    public void before(String name,int age) {
    System.out.println("前置通知");
    System.out.println(name+" "+age);
    }
    public void after() {
    System.out.println("后置通知1");
    }
    public void myaftering() {
    System.out.println("后置通知2");
    }
    public void mythrow() {
    System.out.println("异常通知");
    }
    public Object myaround(ProceedingJoinPoint p) throws Throwable {
    System.out.println("执行环绕通知");
    System.out.println("环绕前置");
    Object result = p.proceed();
    System.out.println("环绕后置");
    return result;
    }
    }
  2. 配置Spring配置文件

    • <aop:after>:后置通知,是否出现异常都执行
    • <aop:after-returning/>:后置通知,只有当切点正确执行时执行。
    • <aop:after><aop:after-returning><aop:after-throwing>执行顺序和配置顺序有关。
    • execution()括号不能加上参数
    • 中间使用and不能使用&& 有spring把and解析成&&
    • args括号里的名称是自定义。顺序和demo1(参数,参数)对应
    • <aop:before>;arg-names=“名称”,名称来源于expression=””中arg(),名称必须一样。
    • args()有几个参数,arg-names里面必须有几个。
    • arg-names里面名称必须和通知方法参数名对应。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <bean id="demo" class="com.gdaib.test.Demo"></bean>
    <bean id="myadvice" class="com.gdaib.advise.MyAdvice"></bean>
    <aop:config>
    <aop:aspect ref="myadvice">
    <aop:pointcut expression="execution(* com.gdaib.test.Demo.demo1(String,int)) and args(name,age))" id="mypoint"/>
    <aop:before method="before" pointcut-ref="mypoint" arg-names="name,age"/>
    <!-- 下面两者的区别在于after不管方法出不出异常都会执行,而后者只能在方法执行正常时才执行 -->
    <!-- <aop:after method="after" pointcut-ref="mypoint"/>
    <aop:after-returning method="myaftering" pointcut-ref="mypoint"/>
    <aop:after-throwing method="mythrow" pointcut-ref="mypoint"/>

    <aop:around method="myaround" pointcut-ref="mypoint"/> -->
    </aop:aspect>
    </aop:config>

使用注解(基于Aspect)

  1. Spring不会自动去寻找注解,必须告诉Spring哪些包下的类可能有注解。
    • 引入xmlns:context。
    1
    <context:component-scan base-package="com.gdaib.advise,com.gdaib.test"></context:component-scan>
  • @Component
    • 相当于<bean/>
    • 如果没有参数,把类名首字母变小写,相当于<bean id=""/>
    • @Component(“自定义名称”)
  1. 实现步骤
  • 在Spring配置文件中设置注解在哪些包中
1
2
3
4
5
6
7
<!-- 如果有多个,使用逗号隔开 -->
<context:component-scan base-package="com.gdaib.advise,com.gdaib.test"></context:component-scan>
<!--
true:使用CGLIB动态代理
false:使用JDK动态代理
-->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
  • 在Demo类中添加@Component,在指定方法上添加切点即@Pointcut注解
1
2
3
4
5
6
7
8
9
@Component
public class Demo {
//添加切点
@Pointcut("execution(* com.gdaib.test.Demo.demo1())")
public void demo1() throws Exception{
//int i=5/0;
System.out.println("demo1");
}
}
  • 在通知类类中配置
    • @Component:表明该类被Spring管理
    • @Aspect:表明该切面使用AspectJ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Component
@Aspect
public class MyAdvice {
@Before("com.gdaib.test.Demo.demo1()")
public void mybefore() {
System.out.println("前置通知");
}
//添加后置通知
/*@After("com.gdaib.test.Demo.demo1()")
public void myafter() {
System.out.println("后置通知");
}*/
@AfterThrowing("com.gdaib.test.Demo.demo1()")
public void mythrow() {
System.out.println("通知异常");
}
//环绕通知
@Around("com.gdaib.test.Demo.demo1()")
public Object myarround(ProceedingJoinPoint p) throws Throwable {
System.out.println("环绕-前");
Object result=p.proceed();
System.out.println("环绕-后");
return result;
}
}

代理设计模式

  1. 设计模式:前人总结的一套解决待定问题的代码;
  2. 代理设计模式优点:
    • 保护真实对象。
    • 让真实对象职责更明确。
    • 扩展。
  3. 代理设计模式
    • 真实对象
    • 代理对象
    • 抽象对象(抽象功能)

    静态代理设计模式

  4. 由代理对象代理真实对象的功能。
    • 自己编写代理类.
    • 每个代理的功能需要单独编写。
  5. 静态代理设计模式的缺点:
    • 当代理功能比较多时,代理类就得代理多个方法。
    • 总结:静态代理模式代码的可重用性差。

    动态代理

  6. 为了解决静态代理频繁编写代理功能的缺点。
  7. 分类:
    • JDK提供的
    • CGLIB

    JDK动态代理

  8. 和CGLIB动态代理的比较
    • JDK自带,不需要导入第三方jar包
    • 缺点:真实对象必须实现接口;利用反射机制,效率不高;

    CGLIB动态代理

  9. 优点:基于字节码操作,生成真实对象的子类。
    • 效率比JDK动态代理高
    • 不需要实现接口
  10. 缺点,需要导入jar包.
  11. 使用SpringAOP时,只要出现Proxy和真实对象转换异常
    1
    2
    3
    4
    5
    <!-- 
    true:使用CGLIB动态代理
    false:使用JDK动态代理
    -->
    <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

自动驻入

  • 在spring配置文件中对象名和ref="id"id名相同时使用自动注入,可以不配置property
  • 两种配置方法
    • <bean>中通过autowire=""配置,只对<bean>生效。
    • <beans>中通过default-autowire=""配置,表当当前文件中所有<bean>都是全局配置内容。
  • autowire可取值
    • default:默认值,根据全局default-autowire=""值。默认全局和局部都没有配置情况下。相当于no.
    • no:默认全局和局部都没有配置情况下。
    • byName:通过名称自动注入,在spring容器中找类id
    • byType:根据类型注入。
      • Spring容器中不可以出现两个相同类型的<bean/>
    • construtor:根据构造方法注入
      • 提供对应参数的构造方法(构造方法参数中包含注入对象那个)
      • 底层使用byName,构造方法参数名和其他<bean>的id相同。

    spring中加载properties文件

  1. 在src下新建xxx.properties文件

  2. 在spring的配置文件中添加xmlns:context,在下面添加

    • 如果需要加载多个配置文件,需要用逗号隔开
    1
    <context:property-placeholder location="classpath:db.properties"/>
  3. 添加属性配置文件记载,并且在<beans>中开启自动注入注意的地方

    • sqlSessionFactoryBean中的id不能叫sqlSessionFactory
    • 修改:把原来通过ref引用替换成value赋值,自动注入只能影响ref,不能影响value赋值
    1
    2
    3
    4
    5
    6
    <!-- 配置扫描器 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.gdaib.mapper"></property>
    <!-- <property name="sqlSessionFactory" ref="factory"></property> -->
    <property name="sqlSessionFactoryBeanName" value="factory"></property>
    </bean>
  4. 在被spring管理的类中通过@value("${key}")取出properties中的值

    • 添加注解扫描
    1
    2
     <!-- 扫描注解 -->
    <context:component-scan base-package=""></context:component-scan>
  • 在类中添加
    • key和变量名可以不相同
    • 变量类型任意,只要保证key对应点的value能转换成这个类型就可以。
1
2
@Value("${key}")
private String test;

scope属性

  1. <bean>的属性
  2. 作用:控制对象有效范围(单例,多例等)
  3. <bean/> 标签对应的对象都是单例
  4. scope可取值
    • singleton:默认值,单例
    • prototype:多例,每次获取重新实例化
    • request:每次请求重新实例化
    • session:每个会话对象内,对象是单例的。
    • application:每个application范围内,对象是单例的。
    • global session spring推出的一个对象,依赖于spring-webmvc-portlet,类似于session

    单例设计模式

  5. 作用:在应用程序中保证最多只有一个实例
  6. 好处:
    • 提升运行效率。
    • 实现数据共享.实例:application对象
  7. 懒汉式
    • 对象只有被调用,才会去创建对象
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    package com.gdaib.singleton;

    public class SingleTon {
    private static SingleTon singleTon;
    /***
    * 方法名和类型相同
    * 无返回值
    *
    * 其他类不能实例化这个类
    */
    private SingleTon() {}
    /***
    * 实例方法,实例方法必须通过对象调用
    * 设置方法为静态方法
    * @return
    */
    public static SingleTon getInstance() {
    if(singleTon==null) {
    //多线程访问下,可能出现线程安全
    synchronized (SingleTon.class) {
    if(singleTon==null) {
    singleTon=new SingleTon();
    }
    }

    }
    return singleTon;
    }
    }
  • 由于添加了锁,所以导致执行效率较低。
  1. 饿汉式:解决了懒汉式中多线程可能出现多个对象和执行效率低的情况
  • 在类被加载时就被实例化
1
2
3
4
5
6
7
8
9
package com.gdaib.singleton;

public class SingleTon {
private static SingleTon singleTon=new SingleTon();
private SingleTon() {}
public static SingleTon getInstance() {
return singleTon;
}
}

声明式事务

  1. 编程式事务
    • 由程序员编写事务控制代码。
    • OpenSessionInView编程式事务。
  2. 声明式事务:
    • 事务控制代码已由spring写好,程序员只需要声明出哪些方法需要进行事务控制和如何进行事务回滚。
  3. 声明式事务都是针对于ServiceImpl类的方法下
  4. 事务管理器基于通知(advice)的。
  5. 在spring中配置声明式事务
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    <!-- 获取数据源 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC&amp;characterEncoding=utf8"></property>
    <property name="username" value="root"></property>
    <property name="password" value="123456"></property>
    </bean>
    <!-- spring-jdbc.jar -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 配置声明式事务 -->
    <tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
    <!-- 哪些方法需要事务控制 -->
    <!-- 方法以ins开头事务管理 -->
    <tx:method name="ins*"/>
    <tx:method name="del*"/>
    <tx:method name="upd*"/>
    <tx:method name="*"/>
    </tx:attributes>
    </tx:advice>
    <aop:config>
    <!-- 切点范围设置大一点 -->
    <aop:pointcut expression="execution(* com.gdaib.service.impl.*.*(..))" id="mypoint"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="mypoint"/>
    </aop:config>

声明式事务属性解释

  1. name=””:哪些方法需要事务控制,支持通配符配置
  2. readonly=”boolean”:是否是只读事务
    • 如果为true,告诉数据库此事务为只读事务。数据库优化,会对性能有一定的提升,所以只要是查询的方法,建议使用此属性值.
    • 如果为false(默认值):事务需要提交的事务,建议新增,删除,修改
  3. propagation:控制事务传播行为。
    • 当一个具有事务控制的方法被另一个有事务控制的方法调用后,需要如何管理事务。(新建事务?在事务中执行?把事务挂起?报异常)
    • REQUIRED:如果当前有事务,就在事务中执行,如果当前没有事务,则新建一个事务。
    • SUPPORTS:如果当前有事务就在事务中执行,如果当前没有事务,就在非事务状态下执行。
    • MANDATORY:必须在事务内部执行,如果当前有事务,就在事务中执行,如果没有事务就报错。
    • REQUIRES_NEW:必须在事务中执行,如果当前没有事务,则新建事务,如果当前有事务,把当前事务挂起。
    • NOT_SUPPORTED:必须在非事务下执行,如果当前没有事务,正常执行,如果当前有事务,把当前事务挂起。
    • NEVER:必须在非事务状态下执行,如果当前没有事务,则正常执行,如果当前有事务,则报错。
    • NESTED:必须在事务状态下执行,如果没有事务,新建事务,如果当前有事务,创建一个嵌套事务。
  4. isolation=””:事务隔离级别
    • 在多线程和并发访问下如何保证访问到的数据具有完整性。
    • 脏读:一个事务(A)读取到另一个事务(B)中未提交的数据,另一个事务中数据可能进行了改变,此时A事务读取的数据可能和数据库中的数据不一致的,此时认为数据是脏数据,读取脏数据过程叫做脏读。
    • 不可重复读
      • 主要针对的是某行数据(行中某列)
      • 主要针对的操作是修改。
      • 两个读取在通一个事务内。
      • 当事务A第一次读取事务后,事务B对事务A读取的数据进行修改,事务A中再次读取的数据和之前读取的数据不一致,这个过程就叫做不可重复读。
    • 幻读:
      • 主要针对的操作是新增和删除
      • 两次事务的结果
      • 事务A按照特定条件查询出结果,事务B新增了一条符合条件的数据,事务A查询的数据和数据库中的数据不一致的,事务A好像出现了幻觉,这种情况称为幻读。
    • isolation的可能取值及作用:
      • DEFAULT:默认值,由底层数据库自动判断应该使用什么隔离级别。
      • READ_UNCOMMITTED:可以读取未提交事务,可能出现脏读、不可重复读、幻读,但是效率最高。
      • READ_COMMITTED:只能读取其他事务已经提交的数据,可以防止脏读,可能出现不可重复读和幻读。
      • REPEATABLE_READ:读取的数据被添加锁,防止其他事务修改此数据,可以防止不可重复读、脏读,可能出现幻读。
      • REPEATABLE_READ:排队操作,对整个表添加锁,一个事务在操作数据时,另一事物等待事务操作完成后才能操作这个表。这个操作,是最安全也是效率最低的。

    事务回滚

  5. rollback-for=”类异常的全限定路径”
    • 当出现什么异常时需要进行事务回滚。
    • 建议:给定该属性值。手动抛异常时一定要给定该属性值,即throw new Exception()
  6. no-rollback-for=””
    • 当出现什么异常时不回滚事务。

    Spring常用注解

  7. @Component:创建类对象,相当于配置<bean/>
  8. @Service@Component功能相同,@Service写在ServiceImpl上。
  9. @Repository@Component功能相同,该注解通常写在数据访问层上。
  10. @Controller@Component功能相同,该注解通常写在控制器上。
  11. @Resource:Java中的注解;默认按照byName,建议把对象名称和属性名称写一样,如果没有名称对象,按照byType注入;不需要编写get和set方法。
  12. @Autowired:Spring框架中的注解;默认按照byType注入。
  13. @Value获取properties文件中的内容
  14. @Pointcut:定义切点。
  15. @Aspect():定义切面类
  16. @Before():定义前置通知
  17. @After():定义后置通知
  18. @AfterReturning():定义后置通知,必须切点正确执行
  19. @Arround():环绕通知。

    ajax复习

  20. $.ajax
  21. $.get、$.post
  22. $.getJson
  23. $.getScript
  24. ObjectMapper mapper=new ObjectMapper(); mapper.writeValueAsString(对象);把对象转化为JSON格式字符串。

Spring源码下载地址:https://github.com/spring-projects/spring-framework/tags?after=v4.2.5.RELEASE

Spring框架下载地址:https://repo.spring.io/release/org/springframework/spring/

Spring与Mybatis整合的jar包:https://blog.csdn.net/qiangqiang816/article/details/81541188

Maven地址:https://mvnrepository.com/