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只能加载类路径下的配置文件
第三方资源配置
<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>
在业务层抽取通用代码
步骤三 把通知加入spring容器管理
步骤四 在配置文件中配置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();
}
获取返回值
<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动态代理无需要原始被代理对象,动态创建出新的代理对象
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)使用不同策略的对象实现不同的行为方式,策略对象的变化导致行为的变化。
策略模式(Strategy Pattern)使用不同策略的对象实现不同的行为方式,策略对象的变化导致行为的变化。