关于spring5的重要笔记在下面的百度网盘连接中,欢迎大家一起学习
链接:https://pan.baidu.com/s/1Pb-2gGbtLncUD_Uul-1Ivw
提取码:4m4v
下面就我学习过程中的一些容易忘记的点再做一次记录,以便后续复习
**
IOC注入属性
**
在使用set方法注入属性时(无参构造函数+set方法):
<!--当要给一个属性注入其他类型的值时,操作如下-->
<!--1 空值--><property name="baddress"><null/></property>
<!--2 属性值包含特殊符号,首先把<>转义,把带特殊符号内容写到CDATA中-->
<property name="bid">
<value>
<![CDATA[<<南京>>]]><!--输出<<南京>>-->
</value>
</property>
特殊类型的注入
<bean id="student" class="com.it.spring5.collectiontype.Student">
<!--数组类型属性的注入-->
<property name="course">
<array>
<value>java课程</value>
<value>python课程</value>
</array>
</property>
<!--list类型属性的注入-->
<property name="list">
<list>
<value>张三</value>
</list>
</property>
<!--map类型属性的注入-->
<property name="map">
<map>
<entry key="1" value="1.1"></entry>
</map>
</property>
<!--set类型属性的注入-->
<property name="sets">
<set>
<value>111</value>
</set>
</property>
</bean>
bean的生命周期
<!--默认是单实例,即加载配置文件后,getBean获得的是同一个对象,可通过scope来设置为多实例-->
<bean id="myBean" class="com.it.spring5.factorybean.MyBean" scope="prototype">
<!--这里面还有属性init-method="",destroy-method="",可在对应的类中定义两个方法作为初始化和销毁的功能-->
<!--bean的生命周期:
1-通过无参构造创建Bean实例
2-调用set方法注入属性
3-调用初始化方法,需自行配置
4-bean可以使用了
5-调用销毁方法,自行配置,这里销毁是要自行调用的,为前面强转applicationContext.close()-->
自动注入属性
(1)根据属性名称自动注入
<!--实现自动装配
bean 标签属性 autowire,配置自动装配
autowire 属性常用两个值:
byName 根据属性名称注入 ,注入值 bean 的 id 值和类属性名称一样
byType 根据属性类型注入
-->
<bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byName"></bean>
<bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>
(2)根据属性类型自动注入
<bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byType"></bean>
<bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>
spring引入外部配置文件配置数据库连接池
<!--引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.password}"></property>
</bean>
基于注解装配
1、什么是注解
(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值…)
//在注解里面 value 属性值可以省略不写,默认值是类名称,首字母小写,即就是这个bean对象的id
(2)使用注解,注解作用在类上面,方法上面,属性上面
2、Spring 针对 Bean 管理中创建对象提供注解
(1)@Component 一般用于javabean层
(2)@Service 一般用于service层
(3)@Controller 一般用于controller层
(4)@Repository 一般用于dao层
- 上面四个注解功能是一样的,都可以用来创建 bean 实例
开启组件扫描():
spring配置文件中不扫描controller层
<context:component-scan base-package="com.it.spring5">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
springmvc配置文件中只扫描controller层,要加上不许用默认的过滤器,因为他自己配置了
<context:component-scan base-package="com.it.spring5" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
基于注解方式实现属性注入
(1)@Autowired:根据属性类型进行自动装配
@Autowired
private UserDao userDao;
(2)@Qualifier:根据名称进行注入
这个@Qualifier 注解的使用,和上面@Autowired 一起使用
@Autowired //根据类型进行注入
@Qualifier(value = "userDaoImpl1") //根据名称进行注入
private UserDao userDao;
AOP
1、什么是 AOP
(1)面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
(2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能
2、AOP 底层使用动态代理
(1)有两种情况动态代理
第一种 有接口情况,使用 JDK 动态代理 • 创建接口实现类代理对象,增强类的方法
第二种 没有接口情况,使用 CGLIB 动态代理 • 创建子类的代理对象,增强类的方法
但这两种底层原理实现起来都很麻烦,而且有局限,因此我们使用AspectJ这个强大的AOP框架
使用AspectJ实现AOP有两种方式:1-基于XML的声明式AspectJ,2-基于注解的声明式AspectJ
3、AOP术语
1.连接点——类里面哪些方法可以被增强,这些方法称为连接点,注意是可以
2.切入点——哪些方法真正的被增强,称为切入点
切入点表达式
(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构: execution([权限修饰符][空格][返回类型][空格][类全路径][.]方法名称 )
其中,权限修饰符可省略,返回类型*
可代表所有 ,后面的类全路径以及方法名称可以写可写*
,参数类型可写..
代表所有
例如:execution(* com.atguigu.dao.*.* (..))
3.通知(增强)——实际增强的逻辑部分称为通知(增强)
通知有多种类型:
* 前置通知
* 后置通知
* 环绕通知
* 异常通知
* 最终通知
4.切面——把通知应用到切入点的过程,是动作
使用AspectJ实现AOP
1、使用基于XML的声明式AspectJ
这种情况需要在配置文件中配置切入点,切面,通知,标签使用起来十分复杂,不推荐使用
2、使用基于注解的声明式AspectJ
一般实际开发中我们使用这种方法
1、在需要被增强的类如User和增强后的代理类如UserProxy上添加注解创建对应的对象
2、在增强后的代理类如UserProxy上添加注解@AspectJ生成代理对象
3、在 spring 配置文件中开启生成代理对象以及扫描
<!-- 开启 Aspect 生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4、配置不同类型的通知
(1)在增强类UserProxy的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
@Component // 注解创建对象
@Aspect // 生成代理对象
@Order(0) // 当有多个代理类对同一个方法进行增强时,我们可以对其增强设置增强的先后顺序,数字越小越先执行,0开始
public class UserProxy {
// 这里有很多相同的切入点,于是我们可以进行抽取
@Pointcut(value = "execution(* com.it.spring5.AOP_annotation.User.add(..))")
public void pointCut(){}
// before代表的就是前置通知,value的值是execution表达式,指定要增强的方法
@Before(value="execution(* com.it.spring5.AOP_annotation.User.add(..))")
public void beforeAdd(){
System.out.println("before......");
}
// 环绕通知
@Around(value = "pointCut()")
public void aroundAdd(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("around前......");
// 中间执行原始方法,使用下面这条代码
proceedingJoinPoint.proceed();
System.out.println("around后......");
}
// 后置通知
@AfterReturning(value = "pointCut()")
public void afterReturningAdd(){
System.out.println("afterReturning......");
}
// 异常通知
@AfterThrowing(value = "pointCut()")
public void afterThrowingAdd(){
System.out.println("afterThrowing......");
}
// 最终通知
@After(value = "pointCut()")
public void afterAdd(){
System.out.println("after......");
}
}
测试:
@Test
public void testAop(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml");
User user = applicationContext.getBean("user", User.class);// 这里用的是被增强的类,而不是代理类
user.add();
}
总结:没有异常时首先是环绕的前面,然后是before,接着是本体,然后是环绕后,接着是after,最后是AfterReturning
输出:
around前......
before......
本体add........
around后......
after......
afterReturning......
有异常时:没有around后,没有AfterReturning,有afterThrowing
输出:
around前......
before......
本体add........
after......
afterThrowing......
事务操作
1、什么事务
(1)事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败
2、事务四个特性(ACID)
(1)原子性
(2)一致性——操作之前和操作之后总量不变
(3)隔离性——多事务操作时互不影响
(4)持久性
3、事务管理介绍
事务添加到 JavaEE 三层结构里面 Service 层(业务逻辑层)
在 Spring 进行事务管理操作:声明式事务管理——基于XML方式,基于注解方式
在 Spring 进行声明式事务管理,底层使用 AOP 原理
4、事务操作步骤
第一种:基于XML方式:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--2 配置通知-->
<tx:advice id="txadvice">
<!--配置事务参数-->
<tx:attributes>
<!--指定哪种规则的方法上面添加事务,比如这里指定accountMoney方法加事务,第二种表示将以account开头的方法加事务,第三种表示所有方法-->
<tx:method name="accountMoney" propagation="REQUIRED"/>
<!--<tx:method name="account*"/>-->
<!--<tx:method name="*"/>-->
</tx:attributes>
</tx:advice>
<!--3 配置切入点和切面-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pt" expression="execution(* com.it.spring5.service.UserService.*(..))"/>
<!--配置切面-->
<aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
</aop:config>
第二种:基于注解方式:
1、在 spring 配置文件配置事务管理器
<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
2、开启事务注解
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
3、在 service 类上面(或者 service 类里面方法上面)添加事务注解,这个注解里面可以配置事务相关参数。但需要注意的是,在实际开发中,事务的配置信息在配置文件中完成,业务逻辑层只需要添加注解,不需要配置里面的参数
@Transactional,这个注解添加到类上面,也可以添加方法上面,如果把这个注解添加类上面,这个类里面所有的方法都添加事务,如果把这个注解添加方法上面,为这个方法添加事务
事务注解的参数:
1、propagation:事务传播行为——多事务方法直接进行调用,这个过程中事务是如何进行管理的
2、isolation:事务隔离级别
(1)事务有特性成为隔离性,多事务操作之间不会产生影响。不考虑隔离性产生很多问题
(2)有三个读问题:脏读、不可重复读、虚(幻)读
(3)脏读:一个未提交事务读取到另一个未提交事务的数据
例如:数据原本为50,事务B修改这条数据为100,事务A读取到这个100,接着事务B进行回滚,又将这条数据修改为50,这个时候事务A读取到的是50,与前面的读取不一样,这就出现了问题,这就叫脏读,两个事务都没提交,致命问题,不能发生
(4)不可重复读:一个未提交事务读取到另一提交事务修改数据
例如:数据原本50,事务A读取到50,事务B读取到50,将其修改为100后进行提交,由于A没有提交,回滚后继续读,读取到100,与之前的50不一致,这就叫不可重复读,是一种现象,会发生
(5)虚读:一个未提交事务读取到另一提交事务添加数据
(6)解决:通过设置事务隔离级别,解决读问题,默认为可重复读
3、timeout:超时时间
(1)事务需要在一定时间内进行提交,如果不提交进行回滚
(2)默认值是 -1 ,设置时间以秒单位进行计算
4、readOnly:是否只读
(1)读:查询操作,写:添加修改删除操作
(2)readOnly 默认值 false,表示可以查询,可以添加修改删除操作
(3)设置 readOnly 值是 true,设置成 true 之后,只能查询
5、rollbackFor:回滚
(1)设置出现哪些异常进行事务回滚
6、noRollbackFor:不回滚
(1)设置出现哪些异常不进行事务回滚
Spring5框架新功能
1、整个 Spring5 框架的代码基于 Java8,运行时兼容 JDK9,许多不建议使用的类和方法在代码库中删除
2、Spring 5.0 框架自带了通用的日志封装,可以整合其他的第三方日志,如已经整合了Log4j2
1、引入jar包
2、创建log4j2.xml配置文件,注意名义固定不能改,内容基本也是固定的
<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
<configuration status="INFO">
<!--先定义所有的appender-->
<appenders>
<!--输出日志信息到控制台-->
<console name="Console" target="SYSTEM_OUT">
<!--控制日志输出的格式-->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</console>
</appenders>
<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
<!--root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出-->
<loggers>
<root level="info">
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>
手动加入日志内容
public class UserLog {
private static final Logger log = LoggerFactory.getLogger(UserLog.class);
public static void main(String[] args) {
log.info("hello log4j2");
log.warn("hello log4j2");
}
}
3、Nullable注解和函数式注册对象
Spring5 框架核心容器支持@Nullable 注解
@Nullable 注解可以使用在方法上面,属性上面,方法参数里面(即在参数的类型前面写@Nullable),表示方法返回可以为空,属性值可以为空,参数值可以为空
Spring5 核心容器支持函数式风格 GenericApplicationContext,类似lambda表达式,把自己在类里面创建的对象也交给spring管理
// 函数式风格创建对象,交给 spring 进行管理
@Test
public void testGenericApplicationContext() {
//1 创建 GenericApplicationContext 对象
GenericApplicationContext context = new GenericApplicationContext();
//2 调用context的方法对象注册
context.refresh();
context.registerBean("user1",User.class,() -> new User());
//3 获取在 spring 注册的对象
// User user = (User)context.getBean("com.atguigu.spring5.test.User");
User user = (User)context.getBean("user1");
System.out.println(user);
}
4、Spring5 支持整合 JUnit5
1、整合JUnit4
测试类不用写application.getBean了,直接注解加载配置文件,注解注入对象,很方便
@RunWith(SpringJUnit4ClassRunner.class) //单元测试框架
@ContextConfiguration("classpath:bean1.xml") //加载配置文件
public class JTest4 {
@Autowired
private UserService userService; // 直接获得到对象
@Test
public void test1() {
userService.accountMoney();
}
}
2、整合JUnit5
@SpringJUnitConfig(locations = "classpath:bean1.xml")
public class JTest5 {
@Autowired
private UserService userService;
@Test
public void test1() {
userService.accountMoney();
}
}
5、Spring5 框架新功能(Webflux)
学习这个需要有SpringMVC、SpringBoot、Maven、Java8新特性的相关基础才能搞这个,后续我会再更新的