Spring复习 7月22日

本文详细介绍了Spring Boot的基础配置,包括Bean的定义、作用域、生命周期、创建方式(工厂方法与实例工厂)、依赖注入(set注入、构造器注入、集合类型数据注入)以及使用XML配置、注解和`@Autowired`的实践。此外,还涵盖了如何通过`@PropertySource`加载properties文件和团队开发的``用法。
摘要由CSDN通过智能技术生成

Spring复习

基础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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 1.创建spring控制的资源-->
    <bean id="Service" name="Service2" class="SSM.Spring.ServiceImpl"/>
</beans>
基本配置
<bean id="beanId" name="beanName1,beanName2" class="ClassName"></bean>
id:bean的名称,通过id值获取bean

​ class:bean的类型

​ name:bean的名称,可以通过name值获取bean,用于多人配合时给bean起别名

bean属性scope
  • 名称:scope

  • 类型:属性

  • 归属:bean标签

  • 作用:定义bean的作用范围

  • 格式:

<bean scope="singleton"></bean>

取值:

  • singleton:设定创建出的对象保存在spring容器中,是一个单例的对象
    • 单例的时候,这个是创建容器的时候就创建了
  • prototype:设定创建出的对象保存在spring容器中,是一个非单例的对象
    • 加载容器不会创建,获取的时候创建
  • request、session、application、 websocket :设定创建出的对象放置在web容器对应的位置
bean生命周期
  • 名称:init-method,destroy-method

  • 类型:属性

  • 归属:bean标签

  • 作用:定义bean对象在初始化或销毁时完成的工作

  • 格式:

    <bean init-method="init" destroy-method="destroy></bean>
    
  • 取值:bean对应的类中对应的具体方法名

  • 注意事项:

    • 当scope=“singleton”时,spring容器中有且仅有一个对象,init方法在创建容器时仅执行一次

    • 当scope=“prototype”时,spring容器要创建同一类型的多个对象,init方法在每个对象创建时均执行一次

    • 当scope=“singleton”时,关闭容器会导致bean实例的销毁,调用destroy方法一次

    • 当scope=“prototype”时,对象的销毁由垃圾回收机制gc()控制,destroy方法将不会被执行

bean对象创建方式

(1)factory-bean

  • 名称:factory-bean

  • 类型:属性

  • 归属:bean标签

  • 作用:定义bean对象创建方式,使用静态工厂的形式创建bean,兼容早期遗留系统的升级工作

  • 格式:

    <bean class="FactoryClassName" factory-method="factoryMethodName"></bean>
    
  • 取值:工厂bean中用于获取对象的静态方法名

  • 注意事项:

    • class属性必须配置成静态工厂的类名

(2)factory-bean,factory-method

  • 名称:factory-bean,factory-method

  • 类型:属性

  • 归属:bean标签

  • 作用:定义bean对象创建方式,使用实例工厂的形式创建bean,兼容早期遗留系统的升级工作

  • 格式:

    <bean factory-bean="factoryBeanId" factory-method="factoryMethodName"></bean>
    
  • 取值:工厂bean中用于获取对象的实例方法名

  • 注意事项:

    • 使用实例工厂创建bean首先需要将实例工厂配置bean,交由spring进行管理

    • factory-bean是实例工厂的beanId

DI依赖注入
set注入
<bean>
    <property name="propertyName" value="propertyValue" ref="beanId"/>
</bean>

name:对应bean中的属性名,要求该属性必须提供可访问的set方法(严格规范为此名称是set方法对应名称)

​ value:设定非引用类型属性对应的值,不能与ref同时使用

​ ref:设定引用类型属性对应bean的id ,不能与value同时使用

  • 注意:一个bean可以有多个property标签
构造器注入
<bean>
	<constructor-arg name="argsName" value="argsValue />
</bean>

                                            
<constructor-arg index="arg-index" type="arg-type" ref="beanId"/>

​ name:对应bean中的构造方法所携带的参数名

​ value:设定非引用类型构造方法参数对应的值,不能与ref同时使用

​ ref:设定引用类型构造方法参数对应bean的id ,不能与value同时使用

​ type :设定构造方法参数的类型,用于按类型匹配参数或进行类型校验

​ index :设定构造方法参数的位置,用于按位置匹配参数,参数index值从0开始计数,保证注入参数的位置

  • 注意:一个bean可以有多个constructor-arg标签
集合类型数据注入

array,list,set,map,props

格式:

<property>
	<list></list>
</property>

集合类型数据注入——list:

<property name="al">
    <list>
        <value>itheima</value>
        <value>66666</value>
    </list>
</property>

集合类型数据注入——props:

<property name="properties">
    <props>
        <prop key="name">itheima666</prop>
        <prop key="value">666666</prop>
    </props>
</property>
p命名空间:

简化里面的property的ref配置

<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     https://www.springframework.org/schema/beans/spring-beans.xsd">

<bean p:propertyName="propertyValue" p:propertyName-ref="beanId"/>
EL表达式的支持

就是把ref换成value用#{}格式

<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
     <property name="userDao" value="#{userDao}"/>
     <property name="bookDao" value="#{bookDao}"/>
     <property name="num" value="#{666666666}"/>
     <property name="version" value="#{'itcast'}"/>
</bean>
properties文件

开启context命名空间支持

xmlns:context="http://www.springframework.org/schema/context"

加载指定的properties文件

<context:property-placeholder location="classpath:filename.properties">

使用加载的数据

<property name="propertyName" value="${propertiesName}"/>
  • 注意:如果需要加载所有的properties文件,可以使用*.properties表示加载所有的properties文件
  • 注意:读取数据使用**${propertiesName}格式进行,其中propertiesName**指properties文件中的属性名
团队开发
<import resource=“config.xml"/>
//Spring容器加载多个配置文件
new ClassPathXmlApplicationContext("config1.xml","config2.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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">


    <!-- -------------------------------------加载properties文件属性实验-------------------------------------- -->
    <!-- -------------------------------------加载properties文件属性实验-------------------------------------- -->
    <!-- -------------------------------------加载properties文件属性实验-------------------------------------- -->
    <!-- -------------------------------------加载properties文件属性实验-------------------------------------- -->
    <!--1.加载context命名空间的支持-->
    <!--xmlns:context="http://www.springframework.org/schema/context"-->

    <!--2.加载配置文件-->
    <context:property-placeholder location="classpath:*.properties"/>

    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
        <property name="userName" value="${username}"/>
        <property name="password" value="${pwd}"/>
    </bean>
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>

    <bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
        <property name="bookDao" ref="bookDao"/>
    </bean>




    <!-- -------------------------------------团队合作import实验-------------------------------------- -->
    <!-- -------------------------------------团队合作import实验-------------------------------------- -->
    <!-- -------------------------------------团队合作import实验-------------------------------------- -->
    <!-- -------------------------------------团队合作import实验-------------------------------------- -->
    <import resource="applicationContext-user.xml"/>
    <import resource="applicationContext-book2.xml"/>
    <import resource="applicationContext-book.xml"/>

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <property name="num" value="3"/>
    </bean>



    <!-- -------------------------------------加载第三方类库资源实验-------------------------------------- -->
    <!-- -------------------------------------加载第三方类库资源实验-------------------------------------- -->
    <!-- -------------------------------------加载第三方类库资源实验-------------------------------------- -->
    <!-- -------------------------------------加载第三方类库资源实验-------------------------------------- -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring_db"/>
        <property name="username" value="root"/>
        <property name="password" value="itheima"/>
    </bean>


</beans>
ApplicationContext

1.ApplicationContext是一个接口,提供了访问spring容器的API

2.ClassPathXmlApplicationContext是一个类,实现了上述功能

3.ApplicationContext的顶层接口是BeanFactory

4.BeanFactory定义了bean相关的最基本操作

5.ApplicationContext在BeanFactory基础上追加了若干新功能

对比BeanFactory

1.BeanFactory创建的bean采用延迟加载形式,使用才创建

2.ApplicationContext创建的bean默认采用立即加载形式

FileSystemXmlApplicationContext

可以加载文件系统中任意位置的配置文件,而ClassPathXmlApplicationContext只能加载类路径下的配置文件

1591021082290

第三方资源配置
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/spring_ioc"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
</bean>

IOC注解开发

开启启动注解:
<context:component-scan base-package="packageName"/>
bean的定义:
  • 名称:@Component @Controller @Service @Repository

  • 类型:类注解

  • 位置:类定义上方

  • 作用:设置该类为spring管理的bean

  • 范例:

    @Component
    public class ClassName{}
    
  • 说明:

    • @Controller、@Service 、@Repository是@Component的衍生注解,功能同@Component
  • 相关属性

    • value(默认):定义bean的访问id
bean的作用域:
  • 名称:@Scope

  • 类型:类注解

  • 位置:类定义上方

  • 作用:设置该类作为bean对应的scope属性

  • 范例:

    @Scope
    public class ClassName{}
    
  • 相关属性

    • value(默认):定义bean的作用域,默认为singleton
bean的生命周期:
  • 名称:@PostConstruct、@PreDestroy

  • 类型:方法注解

  • 位置:方法定义上方

  • 作用:设置该类作为bean对应的生命周期方法

  • 范例:

@PostConstruct
public void init() { System.out.println("init..."); }
加载第三方资源:@Bean
@Bean("dataSource")
public DruidDataSource createDataSource() {    return ……;    }
    • 因为第三方bean无法在其源码上进行修改,使用@Bean解决第三方bean的引入问题

    • 该注解用于替代XML配置中的静态工厂与实例工厂创建bean,不区分方法是否为静态或非静态

    • @Bean所在的类必须被spring扫描加载,否则该注解无法生效

  • 相关属性

    • value(默认):定义bean的访问id
bean的非引用类型属性注入:
  • 名称:@Value

  • 类型:属性注解、方法注解

  • 位置:属性定义上方,方法定义上方

  • 作用:设置对应属性的值或对方法进行传参

  • 范例:

@Value("${jdbc.username}")
private String username;
    • value值仅支持非引用类型数据,赋值时对方法的所有参数全部赋值

    • value值支持读取properties文件中的属性值,通过类属性将properties中数据传入类中

    • value值支持SpEL

    • @value注解如果添加在属性上方,可以省略set方法(set方法的目的是为属性赋值)

  • 相关属性

    • value(默认):定义对应的属性值或参数值
bean的引用类型属性注入:
@Autowired(required = false)
@Qualifier("userDao")
private UserDao userDao;
  • 说明:

    • @Autowired默认按类型装配,指定@Qualifier后可以指定自动装配的bean的id
  • 相关属性

    • required:定义该属性是否允许为null

优先级配置:@Primary

@Primary
public class ClassName{}

@Autowired默认按类型装配,当出现相同类型的bean,使用@Primary提高按类型自动装配的优先级,多个@Primary会导致优先级设置无效

其他引用类型注解:
  • 名称:@Inject、@Named、@Resource

  • 说明:

    • @Inject与@Named是JSR330规范中的注解,功能与@Autowired和@Qualifier完全相同,适用于不同架构场景
    • @Resource是JSR250规范中的注解,可以简化书写格式
  • @Resource相关属性

    • name:设置注入的bean的id

    • type:设置注入的bean的类型,接收的参数为Class类型

加载properties文件: @PropertySource
  • 名称:@PropertySource

  • 类型:类注解

  • 位置:类定义上方

  • 作用:加载properties文件中的属性值

  • 范例:

    @PropertySource(value = "classpath:filename.properties")
    public class ClassName {
        @Value("${propertiesAttributeName}")
        private String attributeName;
    }
    
  • 说明:

    • 不支持*通配格式,一旦加载,所有spring控制的bean中均可使用对应属性值
  • 相关属性

    • value(默认):设置加载的properties文件名

    • ignoreResourceNotFound:如果资源未找到,是否忽略,默认为false

纯注解格式:
@Configuration
@ComponentScan("scanPackageName")
public class SpringConfigClassName{
}
  • 核心配合类用于替换spring核心配置文件,此类可以设置空的,不设置变量与属性

  • bean扫描工作使用注解@ComponentScan替代

第三方bean配置与管理 @Configuration
@Configuration
@Import(OtherClassName.class)
public class ClassName {
}
  • @Import注解在同一个类上,仅允许添加一次,如果需要导入多个,使用数组的形式进行设定

  • 在被导入的类中可以继续使用@Import导入其他资源(了解)

  • @Bean所在的类可以使用导入的形式进入spring容器,无需声明为bean

依赖加载:@DependsOn
  • 说明:

    • 配置在方法上,使@DependsOn指定的bean优先于@Bean配置的bean进行加载

    • 配置在类上,使@DependsOn指定的bean优先于当前类中所有@Bean配置的bean进行加载

    • 配置在类上,使@DependsOn指定的bean优先于@Component等配置的bean进行加载

  • 相关属性

    • value(默认):设置当前bean所依赖的bean的id
@DependsOn("beanId")
public class ClassName {
}

@Order: 控制加载顺序

  • 名称:@Order

  • 类型:配置类注解

  • 位置:配置类定义的位置(类上)

  • 作用:控制配置类的加载顺序

  • 范例:

@Order(1)
public class SpringConfigClassName {
}

**@Lazy:**延迟加载

  • 名称:@Lazy

  • 类型:类注解、方法注解

  • 位置:bean定义的位置(类上或方法上)

  • 作用:控制bean的加载时机,使其延迟加载

  • 范例:

@Lazy
public class ClassName {
}
整合Junit:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class UserServiceTest {
}
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import({JDBCConfig.class,MyBatisConfig.class})
public class SpringConfig {
}
排除不要加载的bean

坐标:

@ComponentScan(
    value="com.itheima",	           //设置基础扫描路径
    excludeFilters =                          //设置过滤规则,当前为排除过滤
	@ComponentScan.Filter(            //设置过滤器
	    type= FilterType.ANNOTATION,  //设置过滤方式为按照注解进行过滤
	    classes=Repository.class)     //设置具体的过滤项,过滤所有@Repository修饰的bean
    )

includeFilters:设置包含性过滤器

​ excludeFilters:设置排除性过滤器

​ type:设置过滤器类型

ImportSelector:排除大量的bean

public class MyImportSelector implements ImportSelector {
    public String[] selectImports(AnnotationMetadata icm) {
        return new String[]{"com.itheima.dao.impl.AccountDaoImpl"};
    }

@Configuration
@ComponentScan("com.itheima")
@Import(MyImportSelector.class)
public class SpringConfig {
}
自定义组件过滤器:
  • 名称:TypeFilter

  • 类型:接口

  • 作用:自定义类型过滤器

public class MyTypeFilter implements TypeFilter {
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory mrf) throws IOException {
        ClassMetadata cm = metadataReader.getClassMetadata();
        tring className = cm.getClassName();
        if(className.equals("com.itheima.dao.impl.BookDaoImpl")){
            return false;
        }
        return false;
    }
}

AOP 切面编程

面向切面编程,一种编程范式,指导开发者,

AOP弥补了OOP的不足,基于OOP基础之上进行横向开发

AOP作用
  • 伴随着AOP时代的降临,可以从各个行业的标准化、规范化开始入手,一步一步将所有共性功能逐一开发完毕,最终以功能组合来完成个别业务模块乃至整体业务系统的开发

  • 目标:将软件开发由手工制作走向半自动化/全自动化阶段,实现“插拔式组件体系结构”搭建

AOP优势
  • 提高代码的可重用性

  • 业务代码编码更简洁

  • 业务代码维护更高效

  • 业务功能扩展更便捷

切入点:是指:共性方法,

连接点:是所有方法

共性功能:通知

切面:切入点和通知的关系

XML方式操作AOP

导入坐标:

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

在业务层抽取通用代码

1591282302976

步骤三 把通知加入spring容器管理

1591282320624

步骤四 在配置文件中配置aop的配置

<!--aop配置-->
<aop:config>
    <!--配置切入点-->
    <aop:pointcut id="pt" expression="execution(* *..*())"/>
    <!--配置切面-->
    <aop:aspect ref="myAdvice">
        <!—通知与切入点之间的关系-->
        <aop:before method="logAdvice" pointcut-ref="pt"/>
    </aop:aspect>
</aop:config>
XMLAOP配置
aop:config:设置AOP
<beans>
    <aop:config>……</aop:config>
    <aop:config>……</aop:config>
</beans>

一个beans标签中可以配置多个aop:config标签

aop:aspect:设置具体的AOP通知对应的切入点
<aop:config>
    <aop:aspect ref="beanId">……</aop:aspect>
    <aop:aspect ref="beanId">……</aop:aspect>
</aop:config>
  • 说明:

    一个aop:config标签中可以配置多个aop:aspect标签

  • 基本属性:

    • ref :通知所在的bean的id
aop:pointcut:设置切入点
<aop:config>
    <aop:pointcut id="pointcutId" expression="……"/>
    <aop:aspect>
        <aop:pointcut id="pointcutId" expression="……"/>
    </aop:aspect>
</aop:config>
切入点表达式的组成
  • 切入点描述的是某个方法

  • 切入点表达式是一个快速匹配方法描述的通配格式,类似于正则表达式

    关键字(访问修饰符  返回值  包名.类名.方法名(参数)异常名)
    

​ 关键字:描述表达式的匹配模式(参看关键字列表)

​ 访问修饰符:方法的访问控制权限修饰符

​ 类名:方法所在的类(此处可以配置接口名称)

​ 异常:方法定义中指定抛出的异常

  • 范例:

    execution(public User com.itheima.service.UserService.findById(int))
    
切入点表达式——通配符
  • *:单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现

    execution(public * com.itheima.*.UserService.find*(*))
    

​ 匹配com.itheima包下的任意包中的UserService类或接口中所有find开头的带有一个参数的方法

  • … :多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写

    execution(public User com..UserService.findById(..))
    

​ 匹配com包下的任意包中的UserService类或接口中所有名称为findById的方法

  • +:专用于匹配子类类型

    execution(* *..*Service+.*(..))
    
切入点表达式——逻辑运算符
  • && :连接两个切入点表达式,表示两个切入点表达式同时成立的匹配

  • || :连接两个切入点表达式,表示两个切入点表达式成立任意一个的匹配

  • ! :连接单个切入点表达式,表示该切入点表达式不成立的匹配

切入点表达式——范例
execution(* *(..))
execution(* *..*(..))
execution(* *..*.*(..))
execution(public * *..*.*(..))
execution(public int *..*.*(..))
execution(public void *..*.*(..))
execution(public void com..*.*(..)) 
execution(public void com..service.*.*(..))
execution(public void com.itheima.service.*.*(..))
execution(public void com.itheima.service.User*.*(..))
execution(public void com.itheima.service.*Service.*(..))
execution(public void com.itheima.service.UserService.*(..))
execution(public User com.itheima.service.UserService.find*(..))
execution(public User com.itheima.service.UserService.*Id(..))
execution(public User com.itheima.service.UserService.findById(..))
execution(public User com.itheima.service.UserService.findById(int))
execution(public User com.itheima.service.UserService.findById(int,int))
execution(public User com.itheima.service.UserService.findById(int,*))
execution(public User com.itheima.service.UserService.findById(*,int))
execution(public User com.itheima.service.UserService.findById())
execution(List com.itheima.service.*Service+.findAll(..))
通知类型

AOP的通知类型共5种

  • 前置通知aop:before:原始方法执行前执行,如果通知中抛出异常,阻止原始方法运行

    应用:数据校验

  • 后置通知aop:after:原始方法执行后执行,无论原始方法中是否出现异常,都将执行通知

    应用:现场清理

  • 返回后通知aop:after-returning:原始方法正常执行完毕并返回结果后执行,如果原始方法中抛出异常,无法执行

    应用:返回值相关数据处理

  • 抛出异常后通知aop:after-throwing:原始方法抛出异常后执行,如果原始方法没有抛出异常,无法执行

    应用:对原始方法中出现的异常信息进行处理

  • 环绕通知aop:around:在原始方法执行前后均有对应执行执行,还可以阻止原始方法的执行

    应用:十分强大,可以做任何事情

    • 注意around 要有个对原始方法的调用:

    • public Object around(ProceedingJoinPoint pjp) throws Throwable {
          Object ret = pjp.proceed();
          return ret;
      }
      
    • 环绕通知方法相关说明:

      • 方法须设定Object类型的返回值,否则会拦截原始方法的返回。如果原始方法返回值类型为void,通知方 也可以设定返回值类型为void,最终返回null

      • 方法需在第一个参数位置设定ProceedingJoinPoint对象,通过该对象调用proceed()方法,实现对原始方法的调用。如省略该参数,原始方法将无法执行

      • 使用proceed()方法调用原始方法时,因无法预知原始方法运行过程中是否会出现异常,强制抛出Throwable对象,封装原始方法中可能出现的异常信息

通知获取数据

获取参数:

public void before(JoinPoint jp) throws Throwable {
    Object[] args = jp.getArgs();
}

1591284387913

获取返回值

<aop:aspect ref="myAdvice">
    <aop:pointcut id="pt3" expression="execution(* *(..))  "/>
    <aop:after-returning method="afterReturning" pointcut-ref="pt3" returning="ret"/>
</aop:aspect>
public void afterReturning(Object ret) {
    System.out.println(ret);
}
public Object around(ProceedingJoinPoint pjp) throws Throwable {
    Object ret = pjp.proceed();
    return ret;
}

获取异常数据:

AOP注解方式:

开启注解:

aop:aspectj-autoproxy/

@Aspect:设置当前类为切面类
  • 位置:方法定义上方
@Aspect
public class AopAdvice {
}
@Pointcut:使用当前方法名作为切入点引用名称
  • 位置:方法定义上方,把这个放到方法上,相当于过滤,过滤规则
  • 切入点要调用只要类名加方法名,不需要设置成静态
@Pointcut("execution(* *(..))")
public void pt() {
}
@Before:标注当前方法作为前置通知
  • 位置:方法定义上方

里面的参数需要注意和PointCut方法名字一样,要带括号

@Before("pt()")
public void before(){
}
@After 标注当前方法作为后置通知
  • 位置:方法定义上方
@After("pt()")
public void after(){
}
@AfterReturning:标注当前方法作为返回后通知
  • 位置:方法定义上方
@AfterReturning(value="pt()",returning = "ret")
public void afterReturning(Object ret) {
}
@AfterThrowing:注当前方法作为异常后通知
  • 位置:方法定义上方
@AfterThrowing(value="pt()",throwing = "t")
public void afterThrowing(Throwable t){
}
@Around:标注当前方法作为环绕通知
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
    Object ret = pjp.proceed();
    return ret;
}
AOP执行通知顺序:

以方法名字排序为准,类名里面的受类名影响

  • 同一个通知类中,相同通知类型以方法名排序为准

  • 不同通知类中,以类名排序为准

  • 使用@Order注解通过变更bean的加载顺序改变通知的加载顺序

AOP注解驱动
  • 名称:@EnableAspectJAutoProxy

  • 类型:注解

  • 位置:Spring注解配置类定义上方

  • 作用:设置当前类开启AOP注解驱动的支持,加载AOP注解

  • 格式:

@Configuration
@ComponentScan("com.itheima")
@EnableAspectJAutoProxy
public class SpringConfig {
}

AOP底层原型

动态代理——JDK Proxy
public class UserServiceJDKProxy {
    public UserService createUserServiceJDKProxy(final UserService userService){
        //获取被代理对象的类加载器
        ClassLoader classLoader = userService.getClass().getClassLoader();
        //获取被代理对象实现的接口
        Class[] classes = userService.getClass().getInterfaces();
        //对原始方法执行进行拦截并增强
        InvocationHandler ih = new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //前置增强内容
                Object ret = method.invoke(userService, args);
                //后置增强内容
                System.out.println("刮大白2");
                return ret;
            }
        };
        //使用原始被代理对象创建新的代理对象
        UserService proxy = (UserService) Proxy.newProxyInstance(classLoader,classes,ih);
        return proxy;
    }
}

动态代理——CGLIB Enhancer

  • CGLIB(Code Generation Library),Code生成类库

  • CGLIB动态代理不限定是否具有接口,可以对任意操作进行增强

  • CGLIB动态代理无需要原始被代理对象,动态创建出新的代理对象

1591287441096

public class UserServiceImplCglibProxy {
    public static UserServiceImpl createUserServiceCglibProxy(Class clazz){
        //创建Enhancer对象(可以理解为内存中动态创建了一个类的字节码)
        Enhancer enhancer = new Enhancer();
        //设置Enhancer对象的父类是指定类型UserServerImpl
        enhancer.setSuperclass(clazz);
        Callback cb = new MethodInterceptor() {
            public Object intercept(Object o, Method m, Object[] a, MethodProxy mp) throws Throwable {
                Object ret = mp.invokeSuper(o, a);
                if(m.getName().equals("save")) {
                    System.out.println("刮大白");
                }
                return ret;
            }
        };
        //设置回调方法
        enhancer.setCallback(cb);
        //使用Enhancer对象创建对应的对象
        return (UserServiceImpl)enhancer.create();
    }
}

事务

1.当数据库操作序列中个别操作失败时,提供一种方式使数据库状态恢复到正常状态(A),保障数据库即使在异常状态下仍能保持数据一致性(C)(要么操作前状态,要么操作后状态)。

2.当出现并发访问数据库时,在多个访问间进行相互隔离,防止并发访问操作结果互相干扰(I)。

  • 事务特征(ACID)

    • 原子性(Atomicity)指事务是一个不可分割的整体,其中的操作要么全执行或全不执行

    • 一致性(Consistency)事务前后数据的完整性必须保持一致

    • 隔离性(Isolation)事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离

    • 持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

@Transactional
  • 名称:@Transactional

  • 类型:方法注解,类注解,接口注解

  • 位置:方法定义上方,类定义上方,接口定义上方

  • 作用:设置当前类/接口中所有方法或具体方法开启事务,并指定相关事务属性

  • 范例:

    @Transactional(
        readOnly = false,
        timeout = -1,
        isolation = Isolation.DEFAULT,
        rollbackFor = {ArithmeticException.class, IOException.class},
        noRollbackFor = {},
        propagation = Propagation.REQUIRES_NEW
    )
    
声明式事务(纯注解驱动)
  • 名称:@EnableTransactionManagement

  • 类型:类注解

  • 位置:Spring注解配置类上方

  • 作用:开启注解驱动,等同XML格式中的注解驱动

  • 范例:

    @Configuration
    @ComponentScan("com.itheima")
    @PropertySource("classpath:jdbc.properties")
    @Import({JDBCConfig.class,MyBatisConfig.class,TransactionManagerConfig.class})
    @EnableTransactionManagement
    public class SpringConfig {
    }
    
    public class TransactionManagerConfig {
        @Bean
        public PlatformTransactionManager getTransactionManager(@Autowired DataSource dataSource){
            return new DataSourceTransactionManager(dataSource);
        }
    }
    

事务底层原理解析

4.1)策略模式应用

策略模式(Strategy Pattern)使用不同策略的对象实现不同的行为方式,策略对象的变化导致行为的变化。

1591368340720

策略模式(Strategy Pattern)使用不同策略的对象实现不同的行为方式,策略对象的变化导致行为的变化。

1591368370924

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码码哈哈0.0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值