1. Spring

1. Spring概念

1.1 介绍

  • Spring是一个轻量级的开源的JavaEE框架
  • Spring用于解决企业应用开发的复杂性
  • Spring两大核心:IOC(控制反转)和AOP(面向切面)

在这里插入图片描述
1.2 Spring入门案例

  • 导入Spring的4个核心jar包:beans、core、context、expression
  • 创建一个Java类,并创建Spring配置的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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user" class="User"></bean>
</beans>
public void test(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
    User user = context.getBean("user", User.class);
    user.add();
}

2. IOC容器

2.1 IOC介绍

  • IOC把对象的创建和对象之间的调用过程,交给Spring管理
  • 使用IOC的目的:降低耦合度
  • IOC通过xml解析、工厂模式、反射来创建对象
  • IOC容器底层就是对象工厂,通过map保存所有创建好的Bean,并提供外界获取功能
  • IOC用于Bean管理,指Spring创建对象+Spring注入属性

2.2 IOC接口

  • Spring提供了两种实现IOC容器的方式,对应两个接口:BeanFactory 和 ApplicationContext
  • BeanFactory是IOC容器的基本实现,是Spring的内置接口,不提供给开发人员使用。在加载配置文件时不会创建对象,在获取对象时(getBean方法)才创建
  • ApplicationContext是BeanFactory的子接口,提供了更多更强大的功能,用于开发使用。在加载配置文件时就会创建对象
  • ApplicationContext有两个主要的实现类:ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext

2.3 基于xml的Bean管理
2.3.1 xml配置文件创建对象介绍

  • 创建对象:在xml配置文件中使用<bean>标签实现对象的创建
  • <bean>标签中的属性:① id:唯一标识;② class:类的全路径
  • 使用xml创建对象时,默认执行无参构造方法
  • 创建好Java对象好,需要给该对象注入属性,又称为依赖注入(DI)

2.3.2 依赖注入的几种方法

  • 方式一:使用set()方法注入属性。在Java类中编写属性对应的set()方法,并在xml配置文件中使用<property>标签进行配置,该标签是<bean>的子标签
<bean id="user" class="User">
    <property name="age" value="22"></property>
    <property name="name" value="防伪"></property>
</bean>
  • 方式二:使用有参构造器注入属性。在Java类中编写有参构造器,并在xml配置文件中使用<constructor-arg>标签进行配置,该标签是<bean>的子标签
<bean id="user" class="User">
    <constructor-arg name="age" value="22"></constructor-arg>
    <constructor-arg name="name" value="防伪"></constructor-arg>
</bean>
  • 方式三:p名称空间注入。用于简化set()方法注入,在xml文件的头部<beans>标签中添加p名称空间,在<bean>标签中进行属性注入

2.3.3 xml注入其他类型的属性

  • 注入空值:<property name="age"> <null/> </property>
  • 注入特殊符号:<property name="name"> <value><![CDATA[<<防伪>>]]]></value> </property>
  • 注入外部bean:在xml中配置外部类对象对应的<bean>,将该对象注入到其他<bean>中
<bean id="book" class="Book"></bean>

<bean id="user" class="User">
    <property name="book" ref="book"></property>
</bean>
  • 注入内部bean:<property name="book"> <bean id="book" class="Book"></bean> </property>
  • 级联赋值:注入外部bean的操作即为级联赋值。除了在被调用bean中直接配置属性值,还可以在调用bean中通过“id.属性”的方式配置被调用bean的属性值,此时被调用bean对应的Java类中应有属性的get()方法
  • 注入集合:除了直接在<property>标签中配置集合属性,还可以在xml中引入util标签库后,将集合提取出来后调用
<property name="arr">
    <array>
        <value>java</value>
        <value>c++</value>
    </array>
</property>
<property name="list" ref="myList"></property>
<property name="map">
    <map>
        <entry key="aa" value="AA"></entry>
        <entry key="bb" value="BB"></entry>
    </map>
</property>
<property name="set">
    <set>
        <value>mysql</value>
        <value>redis</value>
    </set>
</property>

<util:list id="myList">
    <value>spring</value>
    <value>autumn</value>
</util:list>

2.3.4 工厂Bean

  • Spring有两种类型的bean,普通bean和工厂bean。普通bean在配置文件中定义的类型就是返回类型,工厂bean在配置文件中定义的类型可以和返回类型不同
  • 在xml中配置静态工厂Bean时,class属性指定静态工厂的全类名,通过“factory-method”属性指定工厂类中创建实例的方法,在该Bean的子标签<constructor-arg>中配置方法的传入参数
  • 在xml中配置实例工厂Bean时,class属性指定要创建对象的全类名,通过“factory-bean”属性指定工厂对象对应的Bean,通过“factory-method”属性指定工厂类中创建实例的方法
  • 若一个类实现了FactoryBean接口,Spring自动将该类识别为工厂Bean,在xml文件中配置时不需要通过属性指定为工厂Bean,实现接口中的getObject()方法定义要返回的对象
public class MyBean implements FactoryBean<Book> {
    //定义要返回的bean
    public Book getObject() throws Exception {
        Book book = new Book();
        book.setName("Java");
        return book;
    }
}

2.3.5 Bean的作用域

  • 在Spring中,可以设置创建的bean是单实例还是多实例,默认为单实例
  • 将<bean>标签中的scope属性设置为“prototype”后为多实例(默认为“singleton”单实例)
  • 当scope值为“singleton”时,加载xml配置文件时就会创建对象;若设置为“prototype”时,在调用getBean()方法时才创建对象

2.3.6 Bean的生命周期
对于一般的bean生命周期有5步,而对于实现了BeanPostProcessor接口的bean,若将该bean在xml中进行配置,所有在同一个xml配置文件中的bean均会加入后置处理器,生命周期变为7步

  • 通过构造器创建bean实例
  • 为bean的属性设置值
  • 【若加入bean的后置处理器】把bean实例传递给postProcessBeforeInitialization方法
  • 调用bean的初始化方法(在<bean>标签中用“init-method”属性指定该bean的初始化方法)
  • 【若加入bean的后置处理器】把bean实例传递给postProcessAfterInitialization方法
  • 使用bean
  • 调用close()方法关闭容器,会调动bean的销毁方法(在<bean>标签中用“destroy-method”属性指定该bean的销毁方法)

2.3.7 自动装配

  • 在<bean>标签中手动设置属性值称为手动装配,若根据bean的属性名和属性类型自动将匹配的属性值进行注入,称为自动装配
  • 自动装配只针对对象类型的属性,且该对象要在xml中进行过配置
  • 在<bean>标签中设置autowire属性的值可更改自动装配的类型,“byName”根据属性名注入,“byType”根据属性类型注入

2.3.8 引入外部属性文件

  • 创建properties格式的外部属性文件
  • 在xml配置文件中引入context名称空间,通过<context>标签引入外部属性文件
  • 在<bean>标签中使用表达式“${}”读取外部属性文件
<context:property-placeholder location="test.properties"/>
<bean id="book" class="Book">
    <property name="name" value="${key1}"></property>
</bean>

2.3.9 SpEL(Spring表达式语言)
在xml文件中进行配置时,可以通过“#{}”使用Spring的EL表达式,支持:使用字面量、引用其他bean、引用其他bean的某个属性值、调用非静态方法、调用静态方法、使用运算符

2.4 基于注解的Bean管理
2.4.1 注解介绍

  • 注解是代码的特殊标记,格式:@注解名称(属性名=属性值,属性名=属性值)
  • 注解可以作用在类、方法、属性上
  • 使用注解的目的在于简化xml配置

2.4.2 创建对象的注解
以下四个注解功能一样,都可以用来创建bean实例,为了清晰使用一般用在固定层

  • @Component
  • @Service:一般用在Service层
  • @Controller:一般用在web层(使用Spring整合JavaWeb时,Servlet由Tomcat创建,不能再使用注解交给ioc容器创建,同时Servlet中获取Service对象时也不能使用注解自动注入,需要从ioc容器中获取,Spring提供了名为ContextLoaderListener的监听器,通过该监听器可以在项目启动和关闭时创建和销毁ioc容器
  • @Repository:一般用在DAO层

2.4.3 使用注解创建对象的步骤

  • 引入AOP依赖
  • 开启组件扫描,在xml配置文件中使用<context:component-scan>标签进行扫描配置,“base-package”指定要扫描的目录
  • 组件扫描的配置:use-default-filters=“false”:表示不使用默认filter,在子标签<context:include-filter>中设置要扫描的内容
<context:component-scan base-package="serive,dao" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
  • 创建类,在类上添加注解。注解中的value等同于使用xml配置中的id,若省略,其值等于类名首字母小写
@Component(value = "userService")
public class UserService {

2.4.4 注入属性的注解

  • @AutoWired:根据属性类型自动装配(标注在方法上时会为每个形参自动注入)
  • @Qualifier:根据属性名称自动装配(可标注在形参前)
  • @Resource:根据属性类型与名称自动装配(非Spring官方注解)
  • @Value:注入普通类型属性

2.4.5 使用注解注入属性的步骤

  • 在Service类和Dao类上添加创建对象的注解(注解添加在实现类上,非接口上)
  • 在Service类中添加Dao类型的属性,在该属性上添加注入属性的注解(不需要set方法)
  • @Qualifier要和@AutoWired一起使用,在指定类型的前提下再指定名称
  • 泛型依赖注入:注入一个组件时,它的泛型也是参考标准,Spring可以使用带泛型的父类类型来确定子类的类型
@Service
public class UserService {
	@Value(value = "abc")
    private String name;
    @Autowired
    @Qualifier(value = "userDaoImpl")
    private UserDao userDao;
}

2.4.6 纯注解开发(一般用于SpringBoot)

  • 上述注解开发中,在xml配置文件中只进行了开启组件扫描的配置,若将该配置放置与一个配置类中,即可实现纯注解开发
  • 在一个Java类上加入@Configuration注解可将其作为Spring配置类,替代xml配置文件
  • 在配置类上加入@ComponentScan注解指定要扫描的包
@Configuration
@ComponentScan(basePackages = {"dao","service"})
public class SpringConfig {
}

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);

3. AOP

3.1 AOP介绍
3.1.1 AOP用途与原理

  • 利用AOP可以对业务逻辑的各个部分进行隔离,使得各部分之间的耦合度降低,提高程序的可重用性
  • AOP通过不修改源代码的方式,在主干功能中添加新功能
  • AOP底层使用动态代理实现。有接口的情况下使用JDK动态代理,没有接口的情况下使用CGLIB动态代理
  • JDK动态代理:代理类会实现与被代理类相同的接口,若被代理类没有实现接口就无法使用JDK动态代理
  • CGLIB动态代理:代理类会实现被代理类所有的方法

3.1.2 JDK动态代理底层代码

  • JDK动态代理使用Proxy类中的方法创建代理对象
  • Proxy中的newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法返回指定接口的代理类的实例,将方法调用分派给指定的调用处理程序
  • newProxyInstance方法中的3个参数分别表示:类加载器、增强方法所在类实现的接口、代理对象增强后的方法
public class JDKProxy {
    public static void main(String[] args) {
        Class[] interfaces = {UserDao.class};
        UserDaoImpl userDao = new UserDaoImpl();
        UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
        System.out.println(dao.add(1, 2));
    }
}

class UserDaoProxy implements InvocationHandler {
    private Object obj;

    public UserDaoProxy(Object obj) {
        this.obj = obj;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法之前执行");
        Object res = method.invoke(obj, args);
        System.out.println("方法之后执行");
        return res;
    }
}

3.1.3 AOP术语

  • 连接点:类中可以被增强的方法
  • 切入点:类中实际上被增强的方法
  • 通知(增强):实际上被增强的部分。通知有5种类型:前置通知(@Before)、后置通知(@AfterReturning)、环绕通知(@Around)、异常通知(@AfterThrowing)、最终通知/返回通知(@After)
  • 切面:将通知应用到切入点的过程

3.2 AspectJ
3.2.1 AOP准备工作

  • Spring框架一般基于AspectJ实现AOP操作
  • AspectJ不是Spring组成部分,是独立的AOP框架
  • 基于AspectJ实现AOP操作有两种方式:基于xml配置文件、基于注解(常用)
  • 使用AOP需要导入的jar包有:aop、aspects、cglib、aspectjweaver、aopalliance(后3个包保证在被代理类没有实现接口时也能使用AOP)
  • 切入点表达式语法结构:execution( [权限修饰符] [返回类型] [全类名] . [方法名] ([参数列表]) )

3.2.2 AspectJ注解

  • 创建一个待增强类,类中定义方法
  • 创建增强类,该类中创建的不同方法代表不同通知类型
  • 在Spring配置文件或配置类中,开启注解扫描
  • 使用注解创建待增强类和增强类的对象
  • 在增强类上添加注解@Aspect
  • 在Spring配置文件或配置类中开启生成代理对象
  • 配置不同类型的通知:在增强类中的方法上添加通知类型注解,使用切入点表达式配置
  • 对相同的切入点可用@Pointcut注解进行抽取
  • 若一个待增强方法有多个增强类,可在增强类上添加“@Order(数字)”注解指定执行顺序,数字越小优先级越高
使用配置文件开启生成代理对象:<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
使用配置类开启生成代理对象:@EnableAspectJAutoProxy

@Component
@Aspect
@Order(1)
public class UserProxy {
    @Pointcut(value = "execution(* aop.annotation.User.add(..))")
    public void point() {
    }

    @Before(value = "execution(* aop.annotation.User.add(..))")
    public void before() {
        System.out.println("before!");
    }

    @AfterReturning(value = "point()")
    public void after() {
        System.out.println("after!");
    }
}

3.2.3 AspectJ配置文件
在xml配置文件中配置切入点:

<aop:config>
    <aop:pointcut id="p" expression="execution(* ioc.Book.setName(..))"/>
    <aop:aspect ref="user">
        <aop:before method="add" pointcut-ref="p"/>
    </aop:aspect>
</aop:config>

3.2.4 AOP细节

  • 若被代理类实现了接口,要通过ioc.getBean(接口)获取bean;若被代理类没有实现接口,通过ioc.getBean(被代理类)获取bean。因为加入了AOP之后获取到的bean都是代理类对象
  • 切入点表达式中支持通配符: ∗ * 匹配一个或多个字符、匹配任意一个参数; . . .. ..匹配任意多个参数、匹配任意多层路径
  • 通知方法的执行顺序:@Before→@After→@AfterReturning或@AfterThrowing
  • 在通知方法中加入JoinPoint类型的形参,可获取切入方法的详细信息,如方法参数、方法名等
  • 通知注解的returning参数可指定该通知方法的一个形参用来接收切入方法的返回值
  • 通知注解的throwing参数可指定该通知方法的一个形参用来接收切入方法的异常

4. JdbcTemplate

4.1 JdbcTemplate概述与准备工作

  • Spring框架对JDBC进行了封装,使用JdbcTemplate方便实现对数据库操作
  • 使用JdbcTemplate需要引入的jar包:spring-jdbc、spring-tx、spring-orm
  • 在xml配置文件中配置数据库连接池
  • 配置JdbcTemplate对象,注入DataSource(在JdbcTemplate源码中有DataSource属性的set方法)
  • 创建Service类和Dao类,在Service类中注入Dao对象,Dao类中注入JdbcTemplate对象
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
    <property name="url" value="jdbc:mysql:///users"/>
    <property name="username" value="root"/>
    <property name="password" value="MyNewPass"/>
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"></property>
</bean>

4.2 JdbcTemplate操作数据库

  • 调用JdbcTemplate对象中的update(String sql, @Nullable Object… args)方法执行增删改操作
  • 调用JdbcTemplate对象中的queryForObject(String sql, Class<T> requiredType)方法查询返回某个值
  • 调用JdbcTemplate对象中的queryForObject(String sql, RowMapper<T> rowMapper, @Nullable Object… args)方法查询返回某个对象
  • 调用JdbcTemplate对象中的query(String sql, RowMapper rowMapper)方法查询返回某个集合
  • 调用JdbcTemplate对象中的batchUpdate(String sql, List<Object[]> batchArgs)方法执行批量增删改操作,该方法的第二个参数是一个List集合,集合中的每个元素是一个Object数组,每个数组代表每次执行SQL语句的传入对象
String sql = "insert into t_user(`username`,`status`) values(?,?)";
jdbcTemplate.update(sql, user.getUsername(), user.getStatus());

String sql = "select count(*) from t_user";
Integer count = jdbcTemplate.queryForObject(sql, Integer.class);

String sql = "select id,username,status from t_user where id=?";
User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), id);

String sql = "select * from t_user";
List<User> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<User>(User.class));

String sql = "insert into t_user value(?,?,?)";
int[] ints = jdbcTemplate.batchUpdate(sql, list);

5. 事务管理

5.1 Spring事务管理介绍

  • 事务一般添加到Service层(业务逻辑层)中
  • 在Spring中进行事务管理操作有两种方式:① 编程式事务管理;② 声明式事务管理(使用)
  • 声明式事务管理有两种方式实现:基于注解方式(使用)和基于xml配置文件方式
  • 声明式事务管理底层使用AOP原理
  • Spring中提供了一个PlatformTransactionManager接口作为事务管理器,该接口针对不同的框架提供不同的实现类

5.2 注解方式实现声明式事务管理
5.2.1 操作步骤

  • 在xml配置文件中配置事务管理器
  • 在xml配置文件中引入名称空间tx,开启事务注解
  • 在Service类或Service类的方法上添加事务注解“@Transactional”
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

5.2.2 @Transactional注解上可以进行的参数配置

  • propagation:事务传播行为。Spring定义了7种传播行为,默认为REQUIRED
    在这里插入图片描述
  • isolation:事务隔离级别。Mysql数据库默认使用REPEATABLE READ
    在这里插入图片描述
  • timeout:超时时间(单位:秒)。事务需要在一定时间内提交,若未提交进行回滚。默认为-1,不回滚
  • readOnly:是否只读(只能进行查询操作)。默认为false
  • rollbackFor:回滚(设置出现哪些异常进行事务回滚)。运行时异常默认回滚,编译时异常默认不回滚
  • noRollbackFor:不回滚(设置出现哪些异常不进行事务回滚)

6. Spring5新特性

6.1 新特性介绍

  • 整个Spring5框架的代码基于Java8,运行时兼容JDK9,并将许多不建议使用的类和方法在代码库中删除
  • Spring5自带了通用的日志框架,移除了log4j,使用log4j2
  • Spring5核心容器支持@Nullable注解,该注解可以用在方法、属性、参数上,表示可以为空
  • Spring5核心容器支持函数式风格GenericApplicationContext
  • Spring5支持整合JUnit5单元测试框架
  • 引入了新的spring-webflux模块,一个基于reactive的spring-webmvc,完全的异步非阻塞,旨在使用enent-loop执行模型和传统的线程池模型

6.2 使用log4j2日志框架

  • 导入log4j-api、log4j-core、log4j-slf4j-impl、slf4j-api的依赖
  • 创建一个名为“log4j2.xml”的配置文件,该配置文件中内容一般固定
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Logger name="sel4jTest" level="trace">
            <AppenderRef ref="Console"/>
        </Logger>
        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

6.3 使用函数式风格向Spring容器中注入对象

GenericApplicationContext context = new GenericApplicationContext();
context.refresh();
context.registerBean("user",User.class, () -> new User());
User user = (User) context.getBean("user");
System.out.println(user);

6.4 整合JUnit
原始的单元测试需要手动创建IOC容器的对象,且无法通过注解自动装配。使用Spring整合后的单元测试会自动创建IOC容器的对象,可以自动装配。

  • 导入spring-test依赖
整合JUnit4
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:jdbc.xml")
public class Junit4Test {

整合JUnit5
@SpringJUnitConfig(locations = "classpath:jdbc.xml")
public class Junit5Test {
    @Autowired
    private UserService userService;

    @Test
    public void test1(){
        User user = userService.findUser(1);
        System.out.println(user);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值