本文最后更新于 2022年5月9日 上午
Spring
相关概念
优点
IOC(Inversion of Control):通过容器实现对象的创建,属性赋值,依赖的管理。
DI(Dependency Injection):调用一个对象时,无须在代码中创建被调用者,而是依赖于外部容器,由外部容器自动创建后传递给程序
Spring使用DI实现IOC
Spring使用
配置文件
依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.19.RELEASE</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.2.19.RELEASE</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.19.RELEASE</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.19.RELEASE</version> </dependency>
|
Spring配置文件applicationContext.xml :
1 2 3 4 5 6 7 8 9 10 11
| <?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="service01" class="com.example.service.impl.ServiceImpl"/> <bean id="service02" class="com.example.service.impl.ServiceImpl"/>
<bean id="date01" class="java.util.Date"/> </beans>
|
此时,程序运行时自动一次性创建好两个ServiceImpl对象,一个非自定义的Data对象
使用容器中的对象:
1 2 3 4 5 6 7 8 9 10
| public void testSpringCreateObject() { String config = "spring.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext(config); Services service = (Services) applicationContext.getBean("service01"); service.doSome(); Date date = (Date) applicationContext.getBean("date01"); System.out.println(date.getTime()); System.out.println(date); }
|
基于XML的DI
类中必须要有set方法
applicationContext:
1 2 3 4 5 6 7 8 9
| <bean id="student01" class="com.example.bean01.Student"> <property name="name" value="Azuas"/> <property name="age" value="20"/>
</bean>
<bean id="date01" class="java.util.Date"> <property name="time" value="114514"/> </bean>
|
即一个bean时另一个bean的参数,使用ref=bean_id
applicationContext:
1 2 3 4 5 6 7 8 9 10
| <bean id="student01" class="com.example.bean02.Student"> <property name="name" value="Azuas"/> <property name="age" value="20"/> <property name="school" ref="school01"/> </bean>
<bean id="school01" class="com.example.bean02.School"> <property name="name" value="HUFE"/> <property name="address" value="ChangSha"/> </bean>
|
实体类中构造器:
1 2 3 4 5 6 7
| public Student(String name, int age, School school) { System.out.println("有参构造"); this.name = name; this.age = age; this.school = school;
}
|
applicationContext:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <bean id="student01" class="com.example.bean03.Student"> <constructor-arg name="name" value="Azusa1"/> <constructor-arg name="age" value="20"/> <constructor-arg name="school" ref="school01"/> </bean>
<bean id="student02" class="com.example.bean03.Student"> <constructor-arg index="0" value="Azusa1"/> <constructor-arg index="1" value="20"/> <constructor-arg index="2" ref="school01"/> </bean>
<bean id="school01" class="com.example.bean03.School"> <property name="name" value="HUFE"/> <property name="address" value="ChangSha"/> </bean>
<bean id="file01" class="java.io.File"> <constructor-arg name="parent" value="D:\Java\Spring_Lesson\Lesson2"/> <constructor-arg name="child" value="pom.xml"/> </bean>
|
注入school:
1 2 3 4 5 6 7 8 9 10 11 12
| <bean id="student01" class="com.example.bean04.Student" autowire="byName"> <property name="name" value="Azusa1"/> <property name="age" value="20"/>
</bean>
<bean id="school" class="com.example.bean04.School"> <property name="name" value="HUFE"/> <property name="address" value="ChangSha"/> </bean>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <bean id="student01" class="com.example.bean04.Student" autowire="byType">
<property name="name" value="Azusa1"/> <property name="age" value="20"/>
</bean>
<bean id="midschool01" class="com.example.bean04.MidSchool"> <property name="name" value="HengYang MidSchool"/> <property name="address" value="HengYang"/> </bean>
|
基于注解的DI
applicationContext配置组件扫描器:
1 2 3 4 5 6 7 8
| <context:component-scan base-package="com.example.bean01"/> <context:component-scan base-package="com.example.bean02"/>
<context:component-scan base-package="com.example.bean01;com.example.bean02"/>
|
在类上直接使用注解@Component,@Value
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @Component("student01") public class Student {
@Value("ChenXi") private String name; @Value("22") private Integer age;
public Student() { System.out.println("无参构造"); }
public void setName(String name) { this.name = name; }
public void setAge(Integer age) { this.age = age; }
@Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
|
对引用类型使用Autowire注入
默认ByType
1 2 3 4 5 6 7 8 9 10
| @Component("student01") public class Student {
@Value("Azusa") private String name; @Value("20") private int age;
@Autowired private School school;
|
1 2 3 4 5 6
| @Component("school01") public class School { @Value("HUFE") private String name; @Value("ChangSha") private String address;
|
强制使用ByName,需设置@Qualifier注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Component("student01") public class Student {
@Value("aaa") private String name; @Value("20") private int age;
@Autowired @Qualifier("school01") private School school;
|
1 2 3 4 5 6
| @Component("school01") public class School { @Value("HUFE") private String name; @Value("ChangSha") private String address;
|
对引用类型使用JDK的@Resource注入
1 2 3 4 5 6 7 8
| @Value("aaa") private String name; @Value("20") private int age;
@Resource(name = "school01") private School school;
|
AOP编程
在不修改主业务逻辑的前提下,扩展和增强其功能。Spring采用了JDK的动态代理,CGLIB动态代理
概念
事务处理和日志处理可以理解为两个切面
程序执行过程中明确的点,如方法的调用或特定的异常被抛出。连接点由两个信息确定:
方法(表示程序执行点,即在哪个目标方法)
相对点(表示方位,即目标方法的什么位置,比如调用前,后等)
切入点指声明的一个或多个连接点的集合。通过切入点指定一组方法。
目标对象指将要被增强的对象,即包含主业务逻辑的类对象。
通知表示切面的执行时间, Advice 也叫增强。通知定义了增强代码切入到目标代码的时间点,是目标方
法执行之前执行,还是之后执行等。通知类型不同,切入时间不同。切入点定义切入的位置,通知定义切入的时间。
切入点表达式
1
| execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
|
1
| execution(访问权限 方法返回值 方法声明(参数) 异常类型)
|
modifiers-pattern 访问权限类型
ret-type-pattern 返回值类型
declaring-type-pattern 包名类名
name-pattern(param-pattern) 方法名(参数类型和参数个数)
throws-pattern 抛出异常类型
?表示可选的部分
AspectJ使用
- @Aspect注解
Aspect类上面使用
- @Before前置通知
在目标方法执行之前执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
@Before("execution(public void com.example.bean01.ServicesImpl.anyService(String, Integer))") public void beforeOperation(JoinPoint joinPoint) { System.out.println("Signature: " + joinPoint.getSignature()); System.out.println("Function Name: " + joinPoint.getSignature().getName()); Object[] args = joinPoint.getArgs(); for (Object arg : args) { System.out.println("Arg: " + arg); }
System.out.println("Before Aspect..."); }
|
- @AfterReturning后置通知
在目标方法执行之后执行,可以获取到目标方法的返回值。
1 2 3 4 5 6
| @AfterReturning(value = "execution(boolean com.example.bean02.ServicesImpl.isService(String))", returning = "res") public void afterRetOperation(Object res) { System.out.println("Return: " + res); System.out.println("After Return Aspect..."); }
|
- @Around环绕通知
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Around("execution(* com.example.bean03.ServicesImpl.isService(..))") public Object aroundOperation(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { Object res = null; System.out.println("Around: Before Aspect...");
Object[] args = proceedingJoinPoint.getArgs(); String name = ""; if(args != null && args.length > 0){ Object arg = args[0]; name = (String) arg; }
if("ChenXi".equals(name)) res = proceedingJoinPoint.proceed(); else res = false;
System.out.println("Around: Return Aspect...");
return res; }
|
proceedingJoinPoint.proceed(); 表示目标方法执行,可以获取返回值。故可以在目标方法前后添加想要的功能。
在目标方法抛出异常后执行
1 2 3 4
| @AfterThrowing(value = "execution(* com.example.bean04.ServicesImpl.anyService(..))", throwing = "exception") public void afterThrowingOperation(Exception exception){ System.out.println("Aspect: AfterThrowing..." + exception.getMessage()); }
|
最后一定会执行,不管遇到异常
1 2 3 4 5 6 7
| @After("aspect01()") public void afterOperation(JoinPoint joinPoint) { System.out.println("After Aspect..."); }
@Pointcut("execution(public void com.example.bean01.ServicesImpl.anyService(String, Integer))") public void aspect01(){}
|
整合MyBatis
加入依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.9</version> </dependency>
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.25</version> </dependency>
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.7</version> </dependency>
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.8</version> </dependency>
|
配置druid以及声明MapperScannerConfigurer,不用手动写工具类,自动读取Mapper文件创建对象,
applicationContext.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="url" value="${jdbc_url}"/> <property name="username" value="${jdbc_user}"/> <property name="password" value="${jdbc_password}"/>
<property name="maxActive" value="${jdbc_maxActive}"/> </bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="configLocation" value="classpath:mybatis.xml"/> </bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <property name="basePackage" value="com.example.dao"/> </bean>
|
事务
applicationContext.xml声明事务管理器,加入注解驱动:
1 2 3 4 5
| <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
|
在ServiceImpl中添加事务注解
1 2 3 4 5 6 7 8 9
|
@Transactional @Override public void buyGoods(Integer goodsId, Integer count) {
|
使用AOP来管理事务
只需要在applicationContext.xml配置即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
<tx:advice id="buyAdvice" transaction-manager="dataSourceTransactionManager"> <tx:attributes> <tx:method name="buyGoods" propagation="REQUIRED" isolation="DEFAULT" rollback-for="java.lang.NullPointerException, com.example.except.NotEnoughException"/> </tx:attributes> </tx:advice>
<aop:config> <aop:pointcut id="servicePointCut" expression="execution(* *..service.impl.*.*(..))"/> <aop:advisor advice-ref="buyAdvice" pointcut-ref="servicePointCut"/> </aop:config>
|