Spring5笔记

Spring框架概述

1. 轻量级框架
2. 降低开发复杂性
3. IOC和Aop
4. 优点多多

入门案例

1. 下载spring
2. 导入相关jar包
3. 创建普通类,编写该类方法
4. xml配置
5. 代码编写:加载配置文件,获取配置创建的对象

IOC容器:Inversion Of Control 控制反转

1. IOC底层原理

  • IOC底层原理:xml解析 + 工厂模式 + 反射(单纯使用工厂模式耦合度不够低)
  • IOC过程:
    第一步:xml配置
    第二步:创建工厂类:Class.forName(class属性值).newInstance()

2. IOC接口

  • IOC容器实现的两种方式:
  1. BeanFactory接口,一般是spring内部使用—>获取对象时才创建对象(懒汉式)
  2. ApplicationContext接口:BeanFactory的子接口,更强大—>加载配置文件时就创建对象(饿汉式)----更好,在启动服务器时就已经创建好对象
  • ApplicationContext接口的两个主要实现类:

    FileSystemXmlApplicationContext("带盘符的路径")
    ClassPathXmlApplicationContext("src下的路径")
    

3. IOC操作Bean管理:即Spring创建对象、注入属性

基于xml方式管理bean

创建对象:
  1. xml配置文件中bean标签配置
  2. 中属性:id,class,name(用于struct)
  3. 默认使用无参构造
注入属性:DI(依赖注入)

(1)使用set方法注入:定义类属性及其set方法,配置xml文件<bean><property name="属性名" value="值"></property></bean>
(2)使用有参构造器注入:定义类有参构造方法,配置xml文件<bean><constructor-arg name="方法参数名" value="值"></constructor-arg></bean>
(3)特别地:p名称空间注入:添加p名称空间xmlns:p=".../chema/p",就可以直接在bean标签中添加p:属性=""
(4)注入属性特殊值:

1.null值:不填value,标签中加<null/>
2.属性值含特殊值:<![CDATA[属性值]]>
3.注入外部bean:<property name="属性名" ref="外部bean的id">
4.注入内部bean:<property>中省略value,里面嵌套一个bean---->外部bean也可以实现
5.注入级联赋值:(1)类似注入外部bean的方式;(2)在1的基础上加<property name="级联的bean.属性" value="">(需要内部bean的get方法)
6.注入数组:<property>中加入<array><value></value></array>
7.注入List:<property>中加入<list><value></value></list>
8.注入set:<property>中加入<set><value></value></set>
9.注入Map:<property>中加入<map><entry key="" value=""></map>
10.集合里的值为对象类型:<property>中加入<list><ref bean="另一个bean的id"></ref></list>
11.把集合注入提取为公共部分:添加util名称空间-xmlns:util="...",xsi:schemaLocation="...",<util:list id="公共标识"><value></value></util:list>
两种bean
  1. 普通bean:配置文件中class属性就决定了返回的类型
  2. FactoryBean:配置文件中class属性和返回的类型可以不一样,创建一个类实现FactoryBean接口,重写方法getObject()定义要返回的类型
bean的作用域:

bean标签中scope属性设置创建的bean实例是单例(默认)还是多例

值为singleton:创建单例对象,在加载配置文件时就创建
值为prototype:创建多例对象,在getBean()时才创建对象
值为request:会把创建的对象放到request域中(了解)
值为session:会把创建的对象放到session域中(了解)
bean的生命周期:
(1)通过无参构造器创建bean实例
(2)调用set方法为bean属性赋值或引用其他bean
(~)调用把bean实例传递给bean后置处理器(BeanPostProcessor)的方法--postProcessBeforeInitialization
(3)调用bean的初始化方法(需手动配置)---<bean init-method="bean类中的方法名">
(~)调用把bean实例传递给bean后置处理器(BeanPostProcessor)的方法--postProcessAfterInitialization
(4)使用bean
(5)调用bean的销毁方法(需手动配置)---<bean destroy-method="bean类中的方法名">,ClassPathXmlApplicationContext.close()
xml自动装配:
很少用到,一般用注解
<bean>标签属性autowire="byName"----->根据属性名称自动装配
<bean>标签属性autowire="byType"----->根据类型自动装配	
引入外部属性文件(properties):
(1)引入context名称空间
(2)<context:property-placeholder location="classpath:properties路径" />
(3)<property>的value="${key}"

基于注解方式管理bean:

bean管理创建对象的注解:

功能都是创建对象

@Component
@Service-----service层
@Controller-----web层
@Repository------dao层
创建对象:
1. 引入aop依赖
2. 开启组件扫描:引入context名称空间,<context:component-scan base-package="扫描包路径">
3. 在类前加@注解(value="实例对象名")----括号内容不写默认实例对象名为小驼峰类名
组件扫描细节配置
<!--示例 1
use-default-filters="false" 表示现在不使用默认 filter,自己配置 filter
context:include-filter ,设置扫描哪些内容
-->
<context:component-scan base-package="com.atguigu" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--示例 2
下面配置扫描包所有内容
context:exclude-filter: 设置哪些内容不进行扫描
-->
<context:component-scan base-package="com.atguigu">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
注入属性:
  1. @Autowired:根据属性类型注入

  2. @Qualifier:根据属性名称注入,配合@Autowired使用

    第一步:创建service类和dao类并在类前添加创建对象注解
    第二步:在service类中的dao属性前加@Autowired注解,若dao实现类有多个,可以加@Qualifier(value="dao实现类名")
    
  3. @Resource:根据名称类型都可,不属于spring,来自java扩展包

    @Resource:根据类型注入
    @Resource(name="dao实现类名"):根据属性名称注入
    
  4. @Value:普通类型注入

    在属性前@Value(value="属性值")
    
纯注解开发:
1@Configuration+@ComponentScan(basePackages={"扫描包路径"}) 注解一个配置类,代替xml配置
(2new AnnotationConfigApplicationContext(配置类)

AOP

什么是AOP

面向切面编程,降低业务逻辑各部分耦合度
通俗描述:不通过修改源代码的方式,在主干功能里添加新功能

AOP底层原理

底层使用的是动态代理来增强方法:

​1. 有接口情况,使用JDK动态代理
在这里插入图片描述

​2. 无接口情况,使用CGLIB动态代理

在这里插入图片描述

JDK动态代理底层实现

public class ProxyTest {
    public static void main(String[] args) {
        Class[] interfaces = {UserDao.class};
        UserDao userDao = new UserDaoImpl();
        UserDao proxyInstance =(UserDao)Proxy.newProxyInstance(ProxyTest.class.getClassLoader(), interfaces, new ProxyUserDao(userDao));
        System.out.println(proxyInstance.add(12,3));

    }
}
class ProxyUserDao implements InvocationHandler{
    private Object obj;
    public ProxyUserDao(Object obj){
        this.obj = obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("原方法之前执行"+method.getName()+">>>>"+ Arrays.toString(args));
        Object res = method.invoke(obj, args);
        System.out.println("原方法之后执行"+obj);
        return res;
    }
}

AOP操作术语

  1. 连接点:类中可以被增强的方法

  2. 切入点:实际要增强的方法

  3. 通知(增强):实际增加的逻辑代码

    通知类型:

    • 前置通知:@Before(value=“切入点表达式”)
    • 环绕通知:@Around(value=“切入点表达式”)
    • 异常通知:@AfterThrowing(value=“切入点表达式”)
    • 最终通知:@After(value=“切入点表达式”)—方法后执行,出异常也执行
    • 后置通知:@AfterReturning(value=“切入点表达式”)—返回值之后执行,出异常不执行
  4. 切面:把通知应用到切入点的过程

切入点表达式

作用:知道增强哪个类哪个方法

execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表]))
execution(* com.spring.dao.add(..));//某个类某个方法
execution(* com.spring.dao.*(..));//某个类所有方法
execution(* com.spring.*.*(..));//包下所有类所有方法

基于AspectJ实现AOP操作

AspectJ是一个独立的AOP框架,使用需引入相关依赖

1. 基于xml配置文件(了解)

  1. 创建增强类,编写不同方法代表不同通知类型

  2. xml中配置

  3. xml中配置aop

    <aop:config>
        <aop:pointcut id="切入点名" expression="切入点表达式"/>
        <aop:aspect ref="增强类名">
        	<aop:before method="增强的方法名" pointcut-ref="切入点名" />
        </aop:aspect>
     </aop:config>
    

2. 基于注解(常用)

使用步骤
  1. 创建增强类,编写不同方法代表不同通知类型

  2. 在Spring配置文件中,使用context、aop名称空间开启注解扫描

    <context:component-scan base-package="扫描包路径"></context:component-scan>			
    
  3. 在被增强类和增强类前加创建对象注解

  4. 在增强类前加@Aspect生成代理对象

  5. <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    
  6. 编写不同类型的通知,在通知方法前加通知类型注解

    //特别的:
    @Around(value="execution(....)")
    public void around(ProceedingJoinPoint proceedingJoinPoint){
    	//环绕之前的代码
    	proceedingJoinPoint.proceed();
    	//环绕之后的代码
    }
    
抽取公共切入点:
  ```java
  @Pointcut(value="共用的切入点表达式")//写在增强类的一个方法前,其他方法使用@注解(value="方法名()")
  ```
设置增强类优先级:
  ```
  @Order(数字)//加在增强类前,值越小优先级越高
  ```
全注解开发:
  1. 编写config类,类前加注解:

    @Configuration
    @ComponentScan(basePackages={"扫描包路径"})  //开启注解扫描
    @EnableAspectJAutoProxy(proxyTargetClass=true)
    

JdbcTemplate

JdbcTemplate是什么

Spring框架对JDBC的封装

JdbcTemplate使用步骤

  1. 导包

  2. 配置文件中配置数据库连接池

  3. 配置JdbcTemplate对象,并注入dataSource属性

    <context:property-placeholder location="jdbc.properties"></context:property-placeholder>
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
            <property name="url" value="${url}"></property>
            <property name="username" value="${user}"></property>
            <property name="password" value="${password}"></property>
            <property name="driverClassName" value="${driver}"></property>
        </bean>
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    
  4. 以service类和dao类为例,在类前添加创建对象注解,在service类中注入dao,在dao中注入JdbcTemplate

    	//在dao中注入jdbcTemplate
    	@Autowired
        private JdbcTemplate jdbcTemplate;
    

JdbcTemplate操作数据库

  1. 添加、修改、删除

    jdbcTemplate.update(String sql,Object ... args)
    
  2. 查询返回某个值

    jdbcTemplate.queryForObject(String sql,Class<T> requiredType)  //这是的Class<T>是返回类型的Class,如Integer.class
    
  3. 查询返回某个对象

    jdbcTemplate.queryForObject(String sql,RowMapper<T> rowMapper,Object ...args)
    //RowMapper<T>是一个接口,需要的是其实现类对象,完成数据封装:
    new BeanPropertyRowMapper<T>(T.class)
    
  4. 查询返回集合

    jdbcTemplate.query(String sql,RowMapper<T> rowMapper,Object ...args)
    //RowMapper<T>是一个接口,需要的是其实现类对象,完成数据封装:
    new BeanPropertyRowMapper<T>(T.class)
    
  5. 批量添加、修改、删除

    batchUpdate(String sql,List<Object[]> batchArgs)
    //Object[]即添加的单个数据,返回int[]
    

Spring中的事务

事务概念回顾

四个特性:ACID

事务一般添加到三层结构中的service层(业务逻辑层)

原始代码处理事务

try{
	//1.开启事务
    //2.业务操作
    //3.提交事务
}catch(Exception e){
    //4.回滚
}

Spring中处理事务

Spring事务管理API

PlatformTransactionManager接口
DataSourceTransactionManager实现类

编程式事务管理(了解)

声明式事务管理(常用)

Spring进行声明式事务管理时,底层使用的是AOP原理

基于xml配置文件方式(了解)
  1. 配置文件中添加事务管理器,并用set方式注入数据源

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
        </bean>
    
  2. 配置通知,配置事务参数,指定哪个方法添加事务

    //配置通知
    <tx:advice id="txadvice">
    	//配置事务参数
        <tx:attributes>
            //指定哪个方法添加事务
        	<tx:method name="方法名" propagation="..."/> //可以用*匹配
        </tx:attributes>	
    </tx:advice>
    
  3. 配置切入点和切面

    <aop:config>
    	<aop:pointcut id="pt" expression="切入点表达式" />
        <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
    </aop:config>
    
基于注解方式(常用)
  1. 配置文件中添加事务管理器,并用set方式注入数据源

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
        </bean>
    
  2. 配置文件中添加tx名称空间,开启事务注解

    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
    
  3. service类或该类方法前加事务注解@Transactional

    @Transactional中可以添加参数:@Transactional(propagation=Propagation.REQUIRED,…)

    1. propagation:事务传播行为:多个事务方法互相调用过程

      事务传播行为有七种:

      REQUIRED(默认):有事务则直接运行,没事务则自己启动事务

      REQUIRED_NEW:直接启动自己的事务,挂起其他事务

    2. isolation:设置事务隔离级别,解决脏读、不可重复读、幻读

    在这里插入图片描述

    1. timeout:超时时间:事务在一定时间内提交,不然就回滚,默认值-1,自定义以秒为单位

    2. readOnly:是否只读,默认为false

    3. rollbackFor:设置哪些异常进行回滚

    4. noRollbackFor:设置哪些异常不进行回滚

    完全注解开发:

    @Configuration  //配置类
    @ComponentScan(basePackages = "com...")  //组件扫描
    @EnableTransactionManagement  //开启事务
    public class config {
        //创建数据库连接池
        @Bean
        public DruidDataSource getDruidDataSource() {
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql:///user_db");
            dataSource.setUsername("root");
            dataSource.setPassword("root");
            return dataSource;
        }
    
        //创建 JdbcTemplate 对象
        @Bean
        public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
    //到 ioc 容器中根据类型找到 dataSource
            JdbcTemplate jdbcTemplate = new JdbcTemplate();
    //注入 dataSource
            jdbcTemplate.setDataSource(dataSource);
            return jdbcTemplate;
        }
    
        //创建事务管理器
        @Bean
        public DataSourceTransactionManager
        getDataSourceTransactionManager(DataSource dataSource) {
            DataSourceTransactionManager transactionManager = new
                    DataSourceTransactionManager();
            transactionManager.setDataSource(dataSource);
            return transactionManager;
        }
    }
    

Spring5新特性

Spring5的代码基于Java8,兼容Java9

Spring5自带通用的日志封装

  1. Spring5移除了Log4jConfigListener,使用Log4j2

  2. Spring5整合Log4j2步骤:

    1. 导包

    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>
      

    也可以手动输出日志:

    Logger log = LoggerFactory.getLogger(所在类.class);
    log.info("输出信息");
    log.warn("输出信息");
    

@Nullable注解

Spring5核心容器支持@Nullable注解,该注解可以用在方法、属性、参数上,表示可为空

函数式风格

Spring5核心容器支持函数式风格GenericApplicationContext

//函数式风格创建对象,交给 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);
    }

整合单元测试

整合JUnit4

  1. 导包

  2. 创建测试类

    @RunWith(SpringJUnit4ClassRunner.class)  //单元测试框架
    @ContextConfiguration("classpath:bean1.xml")  //加载配置文件
    public class JTest4 {
        @Autowired
        private AccountService accountService;
    
        @Test
        public void test1() {
            accountService.accountMoney();
        }
    }
    
    

整合JUnit5

  1. 导包

  2. 创建测试类

    @ExtendWith(SpringExtension.class)
    @ContextConfiguration("classpath:bean1.xml")
    //使用一个复合注解替代上面两个注解完成整合
    //@SpringJUnitConfig(locations="classpath:bean1.xml")
    public class JTest5 {
        @Autowired
        private AccountService accountService;
    
        @Test
        public void test1() {
            accountService.accountMoney();
        }
    }
    

WebFlux(补充)

前置知识:Spring MVC、Spring Boot、Maven、Java 8新特性

WebFlux是什么

  1. 是 Spring5 添加新的模块,用于 web 开发的,功能和 SpringMVC 类似的,Webflux 是使用响应式编程的框架

  2. 使用传统 web 框架,比如 SpringMVC,这些基于 Servlet 容器,Webflux 是一种异步非阻塞的框架,异步非阻塞的框架在 Servlet3.1 以后才支持,核心是基于 Reactor 的相关 API 实现的

  3. 什么是异步非阻塞

    1. 异步和同步针对调用者,调用者发送请求,如果等着对方回应之后才去做其他事情就是同步,如果发送请求之后不等着对方回应就去做其他事情就是异步
    2. 阻塞和非阻塞针对被调用者,被调用者受到请求之后,做完请求任务之后才给出反馈就是阻塞,受到请求之后马上给出反馈然后再去做事情就是非阻塞
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值