typora-root-url: assets
typora-copy-images-to: assets
Spring
1.Spring简介
主要缔造者,著名的Spring之父,Rod Johnson,非常有意思的是他是计算机本科,音乐博士学位
他是轮子理论的推崇者
轮子理论 :不要重复的造轮子(意思就是直接用写好的代码,不要每次都重新写一样的代码,不重新发明技术,而是让原有的技术使用起来更加方便)
Spring不像Mybatis那样是属于哪一层的框架,它存在 “everywhere”
2.Spring三大核心
- IOC/DI (控制反转/依赖注入)
- AOP 面向切面编程
- 声明式事务
3.Spring模块
Spring框架的功能被有组织的分散到约20个模块中。这些模块分布在核心容器,数据访问/集成,Web,AOP(面向切面的编程),植入(Instrumentation),消息传输和测试,如下面的图所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tU5uhv6y-1573126039702)(/spring-overview.png.pagespeed.ce.XVe1noRCMt.png)]
Test :测试单元模块,用来处理测试用例
Core Container : 核心容器模块 ,使用Spring最基础的条件,不可或缺
- 1.Beans : 负责创建对象和管理对象
- 2.Core : 核心类,提供一些核心类库
- 3.Context : 上下文参数,获取外部资源,或者管理注解等
- 4.SpEL : 表达式语言,对应expression.jar包
AOP : 实现AOP功能需要的依赖
Aspects : 切面,AOP 依赖包
Instrumentation : 工具类
Messaging : 消息处理
Data Access/Integration : spring封装数据访问层内容
- 1.JDBC : Spring对JDBC的封装
- 2.ORM:封装了持久层框架的代码,例如Hibernate(但并没有对Mybatis进行封装)
- 3.Transactions :对应soring-tx.jar,声明式事务时需要导入
Web : 需要完成Web相关功能时需要,例如:需要Tomcat加载Spring配置文件时需要
4.Spring之IOC/DI
IOC (Inversion of Control) 控制反转
IOC是什么 :原来由程序员主动 new 对象这一行为转交给Spring负责(即对象的控制权反转了)
IOC的作用 :解耦(程序员不需要管理对象,解开了程序员与对象的耦合)
例如我们都学过Mybatis,经历过创建工厂对象,获取sqlSession,这些管理对象的代码如果用Spring去管理将大大便利我们的开发
DI依赖注入是什么 :它本质上与IOC完全一样,只是角度不同,对于原有的应用程序来说对象的控制权反转了,但对于spring容器来说,相当于spring在向一个类中注入对象
5.IOC/DI初体验
5.1引入依赖
创建maven项目,引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.neuedu</groupId>
<artifactId>spring_yzn</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- 核心容器 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.7</version>
</dependency>
</dependencies>
</project>
5.2创建实体类
package org.neuedu.spring;
public class Student {
private int stuno;
private String name;
public int getStuno() {
return stuno;
}
public void setStuno(int stuno) {
this.stuno = stuno;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
5.3创建配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!--
xmlns : 命名空间,在后面还可以看见与之对应的.xsd文件,它们共同决定
着在根节点中能使用什么样的便签以完成不同的配置
-->
<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="stu" class="org.neuedu.spring.Student"></bean>
</beans>
日志配置文件log4j.properties
log4j.rootLogger=DEBUG,A1
log4j.logger.org.apache=DEBUG
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n
5.4创建测试类StudentTest.java
package org.neuedu.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class StudentTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Student stu = applicationContext.getBean("stu", Student.class);
System.out.println(stu);
}
}
控制台打印,没有输出NULL说明对象已经创建出来了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4WnWLO4g-1573126039706)(/1570451511680.png)]在实体类中我们并没有添加任何构造器,所以Spring创建对象默认选择的是无参构造器,可以自己测试一下
在这个示例中,貌似Spring造成我们在获取对象时,反倒代码多了,但是想象一下,如果这个对象在100个类中被调用,当需要修改时,使用Spring只需要修改一下配置文件便可,而以前却需要一个一个去修改,从这个角度看,使用Spring是非常必要的,但上述示例只是一个简单的例子,Spring虽然能管理所有对象,但在项目中也是分场景使用的,不是什么对象都一定要用Spring管理的,杀鸡焉用牛刀的道理相信大家都明白的
5.5创建对象的三种方式(了解)
5.5.1通过构造方法创建(有参,无参)
在上述示例中
<?xml version="1.0" encoding="UTF-8"?>
<!--
xmlns : 命名空间,在后面还可以看见与之对应的.xsd文件,它们共同决定
着在根节点中能使用什么样的便签以完成不同的配置
-->
<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="stu" class="org.neuedu.spring.Student"></bean>
</beans>
采取的默认无参构造器创建的对象,如何指定有参构造器创建对象呢?非常简单
添加有参构造器
package org.neuedu.spring;
public class Student {
private int stuno;
private String name;
public Student() {}
public Student(int stuno, String name) {
this.stuno = stuno;
this.name = name;
}
}
修改配置xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
xmlns : 命名空间,在后面还可以看见与之对应的.xsd文件,它们共同决定
着在根节点中能使用什么样的便签以完成不同的配置
-->
<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="stu" class="org.neuedu.spring.Student">
<constructor-arg name="stuno" value="1001"></constructor-arg>
<constructor-arg name="name" value="tom"></constructor-arg>
</bean>
</beans>
测试类
package org.neuedu.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class StudentTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Student stu = applicationContext.getBean("stu", Student.class);
System.out.println(stu.getName());
}
}
控制台
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zn6nFYQn-1573126039708)(/1570451598830.png)]
5.5.2实例工厂
需要创建工厂对象,然后让工厂帮助我们创建对象
工厂类
public class StudentFactory {
public Student getInstance(){
return new Student(1002,"mike");
}
}
配置文件
<?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 class="org.neuedu.spring.StudentFactory" id="factory"></bean>
<bean id="stu" factory-bean="factory" factory-method="getInstance"></bean>
</beans>
测试类
package org.neuedu.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class StudentTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Student stu = applicationContext.getBean("stu", Student.class);
System.out.println(stu.getName());
}
}
启动测试
5.5.3静态工厂
不需要创建工厂对象,直接调用工厂方法创建对象
将上述实例工厂稍加改造就是静态工厂
package org.neuedu.spring;
public class StudentFactory {
public static Student getInstance(){
return new Student(1002,"mike");
}
}
配置文件
<?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="stu" class="org.neuedu.spring.StudentFactory" factory-method="getInstance"></bean>
</beans>
启动测试
5.6属性赋值
依赖注入有三种方式:构造器注入,setter注入,接口注入(Spring不支持)
5.6.1构造器赋值(注入)
<?xml version="1.0" encoding="UTF-8"?>
<!--
xmlns : 命名空间,在后面还可以看见与之对应的.xsd文件,它们共同决定
着在根节点中能使用什么样的便签以完成不同的配置
-->
<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="stu" class="org.neuedu.spring.Student">
<constructor-arg name="stuno" value="1001"></constructor-arg>
<constructor-arg name="name" value="tom"></constructor-arg>
</bean>
</beans>
5.6.2setter方法赋值(注入)
<?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">
<!--setter注入-->
<bean id="stu" class="org.neuedu.spring.Student">
<property name="stuno" value="123"></property>
<property name="name" value="lilei"></property>
</bean>
<!--这样写也可以,与上面等效,二选一-->
<bean id="stu" class="org.neuedu.spring.Student">
<property name="stuno">
<value>123</value>
</property>
<property name="name">
<value>lilei</value>
</property>
</bean>
</beans>
启动测试
5.6.3各类属性赋值(注入)
Student.java
package org.neuedu.spring;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Student {
private int stuno;
private String name;
private Set<String> set;
private List<String> list;
private String[] array;
private Map<String,String> map;
...
}
配置文件
<?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="stu" class="org.neuedu.spring.Student">
<property name="stuno">
<value>123</value>
</property>
<property name="name">
<value>lilei</value>
</property>
<property name="set">
<set>
<value>set1</value>
<value>set2</value>
<value>set3</value>
<value>set4</value>
</set>
</property>
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
</list>
</property>
<property name="array">
<array>
<value>array1</value>
<value>array2</value>
</array>
</property>
<property name="map">
<map>
<entry key="key1" value="value1"></entry>
<entry key="key2" value="value2"></entry>
</map>
</property>
</bean>
</beans>
还有一种特殊的类型properties,但代码不好演示,这里就单独列出来
<property name="properties">
<props>
<prop key="a">mysql</prop>
<prop key="b">testurl</prop>
</props>
</property>
类似于properties文件中的配置
a=mysql
b=testurl
意思就是properties文件中的配置信息,spring也可以配置类似于properties文件这种属性来完成特殊的功能需求,我们在后续会见到
注意:注入基本数据类型或String类型时,使用value进行注入,如果是另一个对象,需要使用ref注入,当使用ref时,依赖注入就发生了,但本身也是IOC的一种体现,所以IOC和DI本质上是一回事
package org.neuedu.spring;
public class Book {
private String bookName;
...
}
package org.neuedu.spring;
public class Student {
private int stuno;
private String name;
private Book book;
...
}
<?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="stu" class="org.neuedu.spring.Student">
<property name="stuno">
<value>123</value>
</property>
<property name="name">
<value>lilei</value>
</property>
<property name="book">
<!-- bean属性 对应另一个bean的id -->
<ref bean="book111"></ref>
</property>
</bean>
<bean id="book111" class="org.neuedu.spring.Book"></bean>
</beans>
6.Spring简单整合Mybatis
接下来我们来体验一下spring整合其他框架的魅力所在
6.1创建maven项目引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.neuedn</groupId>
<artifactId>spring-mybatis</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!--spring 核心容器-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<!--spring jdbc 数据源需要-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<!--spring 事务-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<!--aop-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<!--整合spring-mybatis的包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.7</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
</project>
####6.2创建applicationContext.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 http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<!--配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis_yzn"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--配置SessionFactory-->
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置mapper扫描器-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 当ref关联的id也叫sqlSessionFactory会出现错误 -->
<property name="sqlSessionFactory" ref="factory"></property>
<!-- 与上一行代码等效,但不会出现错误,推荐使用 -->
<property name="sqlSessionFactoryBeanName" value="factory"></property>
<property name="basePackage" value="org.neuedu.mapper"></property>
</bean>
<bean id="userService" class="org.neuedu.service.UserService">
<property name="userMapper" ref="userMapper"></property>
</bean>
</beans>
log4j.rootLogger=DEBUG,A1
log4j.logger.org.apache=DEBUG
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n
6.3项目结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VARP971q-1573126039711)(/1570539624646.png)]
mapper和xml
package org.neuedu.mapper;
import org.neuedu.bean.User;
import java.util.List;
public interface UserMapper {
List<User> getAllUser();
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.neuedu.mapper.UserMapper">
<select id="getAllUser" resultType="org.neuedu.bean.User">
select * from `user`
</select>
</mapper>
service
package org.neuedu.service;
import org.neuedu.bean.User;
import org.neuedu.mapper.UserMapper;
import java.util.List;
public class UserService {
private UserMapper userMapper;
public UserMapper getUserMapper() {
return userMapper;
}
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
public List<User> getAllUser() {
return userMapper.getAllUser();
}
}
MainTest.java
package org.neuedu;
import org.neuedu.bean.User;
import org.neuedu.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
public class MainTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
String[] names = applicationContext.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
UserService userService = applicationContext.getBean("userService", UserService.class);
List<User> users = userService.getAllUser();
for (User user : users) {
System.out.println(user);
}
}
}
运行测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bXWEdvj9-1573126039713)(/1570539845747.png)]
事务和别名也可以配置,以后讲解
OK!!!现在我们只简单的整合了Mybatis,还不是最终版,后续在SSM整合时会更精简,但已经非常 easy 了不是么
7.AOP
Aspect Oriented Programming : 面向切面编程
针对某一个或一些方法,添加通知,形成横切面的思想就是AOP
简单程序
package org.neuedu;
public class AOPTest {
public void test1() {
System.out.println(1);
}
public void test2() {
System.out.println(2);
}
public void test3() {
System.out.println(3);
}
public static void main(String[] args) {
AOPTest aopTest = new AOPTest();
aopTest.test1();
aopTest.test2();
aopTest.test3();
}
}
现在我们想在原有纵向执行流程中添加横向切面通知
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-02HFjEAN-1573126039715)(/1570541704421.png)]通知就是方法,只不过让它在执行test2前或后自动调用执行
7.1必备概念
- 1.原有功能:切点,pointcut
- 2.前置通知:在切点之前执行的功能,before advice
- 3.后置通知:在切点之后执行的功能,afteradvice
- 4.如果切点执行过程中出现异常,会触发异常通知 throw advice
- 5.所有功能总称 切面
- 6.把切面嵌入到原有功能的过程 称为 织入
7.2小试牛刀
#####7.2.1添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.neuedu</groupId>
<artifactId>aop</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--spring 核心容器-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<!--spring 事务-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<!--aop-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.7</version>
</dependency>
<!--aop依赖jar-->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
</dependencies>
</project>
7.2.2准备代码
package org.neuedu;
public class AOPTest {
public void test1() {
System.out.println(1);
}
public void test2() {
System.out.println(2);
}
public void test3() {
System.out.println(3);
}
public static void main(String[] args) {
// 注意:想要使用aop,必须是spring管理的对象,所以这里不能new
}
}
7.2.3准备通知类
package org.neuedu;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class MyBeforeAdvice implements MethodBeforeAdvice {
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("前置通知");
}
}
package org.neuedu;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class MyAfterAdvice implements AfterReturningAdvice {
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("后置通知");
}
}
7.2.4配置文件
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="beforeAdvice" class="org.neuedu.MyBeforeAdvice"></bean>
<bean id="afterAdvice" class="org.neuedu.MyAfterAdvice"></bean>
<aop:config>
<!--配置切面-->
<aop:pointcut id="pointcut" expression="execution(* org.neuedu.AOPTest.test2())"/>
<aop:advisor advice-ref="beforeAdvice" pointcut-ref="pointcut"></aop:advisor>
<aop:advisor advice-ref="afterAdvice" pointcut-ref="pointcut"></aop:advisor>
</aop:config>
<bean id="aopTest" class="org.neuedu.AOPTest"></bean>
</beans>
7.2.5测试
package org.neuedu;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AOPTest {
public void test1() {
System.out.println(1);
}
public void test2() {
System.out.println(2);
}
public void test3() {
System.out.println(3);
}
public static void main(String[] args) {
// 使用aop,对象必须是spring管理的,所以这里不能new
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
AOPTest aopTest = applicationContext.getBean("aopTest", AOPTest.class);
aopTest.test1();
aopTest.test2();
aopTest.test3();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7FNp4wpD-1573126039717)(/1570545487035.png)]
7.2.6*通配符的含义
<aop:pointcut id="pointcut" expression="execution(* org.neuedu.AOPTest.test2())"/>
org.neuedu.AOPTest类下test2()方法
<aop:pointcut id="pointcut" expression="execution(* org.neuedu.AOPTest.*())"/>
org.neuedu.AOPTest类下的任意无参方法
<aop:pointcut id="pointcut" expression="execution(* org.neuedu.AOPTest.*(..))"/>
org.neuedu.AOPTest类下的任意方法
<aop:pointcut id="pointcut" expression="execution(* org.neuedu.*.*(..))"/>
org.neuedu包下的任意类任意方法
<aop:pointcut id="pointcut" expression="execution(* org.neuedu.*.service.*.*(..))"/>
org.neuedu包下的任意子包下service下任意类任意方法(这种配置在分组项目中是比较常见的)
7.2.7前置通知和后置通知参数(了解)
package org.neuedu;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class MyBeforeAdvice implements MethodBeforeAdvice {
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("前置通知");
}
}
Method method : 切点方法对象
Object[] objects :切点方法参数
Object o:切点方法属于的对象
package org.neuedu;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class MyAfterAdvice implements AfterReturningAdvice {
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("后置通知");
}
}
Object o : 返回值对象
Method method : 切点方法对象
Object[] objects :切点方法参数
Object o1:切点方法属于的对象
7.3AspectJ方式配置AOP
上述配置还可以这样写
定义切面
package org.neuedu;
import org.aspectj.lang.ProceedingJoinPoint;
public class AdviceOfMine {
public void beforeAdvice(){
System.out.println("前置");
}
public void afterAdvice(){
System.out.println("后置");
}
public void throwsAdvice(Exception e){
System.out.println("异常信息:"+e.getMessage());
}
public Object arroundAdvice(ProceedingJoinPoint point) throws Throwable {
System.out.println("环绕前置");
Object proceed = point.proceed();// 放行
System.out.println("环绕后置");
return proceed;
}
}
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="beforeAdvice" class="org.neuedu.AdviceOfMine"></bean>
<aop:config>
<aop:aspect ref="beforeAdvice">
<aop:pointcut id="pointcut" expression="execution(* org.neuedu.AOPTest.test2())"/>
<!--前置通知-->
<aop:before method="beforeAdvice" pointcut-ref="pointcut"></aop:before>
<!--
后置通知
after-returning 不出异常才执行
after 不管出不出异常都执行
-->
<aop:after method="afterAdvice" pointcut-ref="pointcut"></aop:after>
<aop:after-returning method="afterAdvice" pointcut-ref="pointcut">
</aop:after-returning>
<!--异常通知-->
<aop:after-throwing method="throwsAdvice" pointcut-ref="pointcut" throwing="e">
</aop:after-throwing>
<!--环绕通知-->
<aop:around method="arroundAdvice" pointcut-ref="pointcut"></aop:around>
</aop:aspect>
</aop:config>
<bean id="aopTest" class="org.neuedu.AOPTest"></bean>
</beans>
package org.neuedu;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AOPTest {
public void test1() {
System.out.println(1);
}
public void test2() {
System.out.println(2);
}
public void test3() {
System.out.println(3);
}
public static void main(String[] args) {
// 使用aop,对象必须是spring管理的,所以这里不能new
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
AOPTest aopTest = applicationContext.getBean("aopTest", AOPTest.class);
aopTest.test1();
aopTest.test2();
aopTest.test3();
}
}
测试
####7.4.注解配置
注解是为了简化配置文件,但Spring需要编程人员指定一下哪些包下有注解
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 启用注解扫描,如果多个包,用逗号分割 -->
<context:component-scan base-package="org.neuedu.utils"></context:component-scan>
</beans>
先认识四个注解:这四个注解功能都一样,都是代替之前的bean标签,即只要在扫描包的类上加上这四个其中任意一个,该类就已经被Spring所管理了,但是可以从语义上明显感觉出来,后三个注解是在特定的包下使用的,
@Component 组件
@Service service
@Repository 仓库dao
@Controller 控制器
package org.neuedu.utils;
import org.springframework.stereotype.Component;
@Component
public class Test {}
相当于之前的
<bean id="test" class="org.neuedu.utils.Test"></bean>
注解给Test类默认起了id,为类名小写,即test,如果想自定义,可以这样写
package org.neuedu.utils;
import org.springframework.stereotype.Component;
@Component("test123")
public class Test {}
7.5利用注解配置AOP
新建项目
配置文件,配置扫描包
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.neuedu"></context:component-scan>
<!--
开启动态代理
true 代表 cglib动态代理 注解都是基于 cglib做的
false 代表 JDK动态代理
-->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
</beans>
配置切点类
package org.neuedu;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
public class ComponentTest {
@Pointcut("execution(* org.neuedu.ComponentTest.test())")
public void test() {
System.out.println("切点");
}
}
配置切面类
package org.neuedu;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class AdviceOfMine {
@Before("org.neuedu.ComponentTest.test()")
public void beforeAdvice(){
System.out.println("前置");
}
@After("org.neuedu.ComponentTest.test()")
public void afterAdvice(){
System.out.println("后置");
}
@AfterThrowing(value = "org.neuedu.ComponentTest.test()",throwing = "e")
public void throwsAdvice(Exception e){
System.out.println("异常信息:"+e.getMessage());
}
@Around("org.neuedu.ComponentTest.test()")
public Object arroundAdvice(ProceedingJoinPoint point) throws Throwable {
System.out.println("环绕前置");
Object proceed = point.proceed();// 放行
System.out.println("环绕后置");
return proceed;
}
}
测试类
package org.neuedu;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AOPTest {
public static void main(String[] args) {
// 使用aop,对象必须是spring管理的,所以这里不能new
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
ComponentTest cTest = applicationContext.getBean("componentTest", ComponentTest.class);
cTest.test();
}
}
运行结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8tQZJokJ-1573126039719)(/1570685075745.png)]
代理模式的核心作用就是通过代理,控制对对象的访问
如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理实现 AOP;如果目标对象没有实现了接口,则采用 CGLIB 库,Spring 会自动在 JDK 动态代理和 CGLIB 动态代理之间转换。 (cglib和jdk动态代理区别,自行百度)
8.自动注入
package org.neuedu;
public class Warrior {
private int level;
private Weapon weapon;
}
package org.neuedu;
public class Weapon {}
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="warrior" class="org.neuedu.Warrior" autowire="byName"></bean>
<bean id="weapon" class="org.neuedu.Weapon"></bean>
</beans>
autowire="byName"
通过名字自动注入
autowire="byType"
通过类型自动注入(多个时会出现矛盾)
9.Spring加载属性文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XcWIYfiV-1573126039720)(/1570708530514.png)]
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis_yzn
jdbc.username=root
jdbc.password=root
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:db.properties">
</context:property-placeholder>
<!--配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--配置SessionFactory-->
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置mapper扫描器-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="factory"></property>
<property name="basePackage" value="org.neuedu.mapper"></property>
</bean>
<bean id="userService" class="org.neuedu.service.UserService">
<property name="userMapper" ref="userMapper"></property>
</bean>
</beans>
9.1将属性文件中的属性注入到对象属性上
package org.neuedu;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class PropertyTest {
// 这个类必须是Spring管理的才能注入
@Value("${jdbc.driverClassName}")
private String driver;
public void show(){
System.out.println(driver);
}
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
PropertyTest test = applicationContext.getBean("propertyTest", PropertyTest.class);
test.show();
}
}
10.scope属性
scope默认值是singleton,也就是单例的,无论获取这个对象多少次都是一个对象
prototype 是多例
<bean id="warrior" class="org.neuedu.Warrior" autowire="byName" scope="singleton"></bean>
<bean id="warrior" class="org.neuedu.Warrior" autowire="byName" scope="prototype"></bean>
这里提醒下大家复习回顾下单例防止忘记
11.声明式事务
以前我们在JDBC中事务是由程序员编码自己控制的
声明式事务,程序员只需要声明哪些方法需要添加事务控制即可,而这些方法指的就是service层的方法
事务管理器是基于通知的,所以需要写通知
这里需要注意,IDEA给我们的约束中有一个是不对的,需要我自己修改成
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W1qD0nPa-1573126039722)(/1570711412980.png)]
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx">
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<!--配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--配置SessionFactory-->
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置mapper扫描器-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="factory"></property>
<property name="basePackage" value="org.neuedu.mapper"></property>
</bean>
<!-- 声明式事务 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:advice id="txAdivce" transaction-manager="txManager">
<tx:attributes>
<tx:method name="add*"/>
<tx:method name="update*"/>
<tx:method name="del*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="myPointcut" expression="execution(* org.neuedu.service.*.*(..))"/>
<aop:advisor advice-ref="txAdivce" pointcut-ref="myPointcut"></aop:advisor>
</aop:config>
</beans>
11.1事务传播行为(了解)
在事务管理的方法互相调用时发生传播行为,由propagation属性控制如何控制
<tx:attributes>
<!-- "REQUIRED"默认值,有事务就在事务中执行,没有就开启一个事务,最常见 -->
<tx:method name="add*" propagation="REQUIRED"/>
<!-- "SUPPORTS"有事务就在事务中执行,没有就在无事务状态下执行 -->
<tx:method name="update*" propagation="SUPPORTS"/>
<!-- "MANDATORY"有事务就在当前事务中执行,否则就报错-->
<!-- "REQUIRES_NEW"有事务就将其挂起,单独先执行自己的事务-->
<!-- "NOT_SUPPORTED"必须在非事务下执行,没有事务正常执行,否则把当前事务挂起-->
<!-- "Never"必须在非事务下执行,没有事务正常执行,否则抛异常-->
<!-- "Nested"必须在事务下执行,没有事务新建事务,否则创建一个嵌套事务 -->
<tx:method name="del*" propagation="MANDATORY"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
11.2事务隔离级别(了解)
isolation属性 :在多线程或并发访问下如何保证访问到的数据具有完整性
脏读:事务a读取到事务b中未提交的数据,另一个事务数据可能改变了,此时A读取的数据与数据库不一致,此时读取的数据即为脏数据,这种读取到脏数据的现象称为脏读
不可重复读:事务a第一次读取数据,事务b对a读取的数据进行修改,事务a中再次读取的数据和之前读取不一致,主要发生在修改时(比如张三取钱时询问工作人员余额,得到反馈8万,此时张三老婆正在ATM取钱,取了5W,此时张三想取5W发现不够,两次读取结果不一样)
幻读:主要针对新增和删除,事务a按照特定条件查询,事务b新增了一条符合条件的数据,事务a查询的数据与数据库不一致,好像出现了幻觉,称为幻读
isolation属性主要解决的就是这些问题
取值可以是
default 数据库自己判断
read_uncommitted : 可以略去未提交的数据,可能出现脏读,不重复读,幻读,效率最高
read_committed : 只能读取其他事务中已提交的数据,防止脏读,可能出现不可重复读和幻读
repeatble_read : 读取的数据会被添加锁,防止其他事务修改此数据,可以防止不可重复读,脏读,可能出现幻读
SERIALIZABLE : 排队操作,对整个表加锁,一个事务在操作时,另一个事务需要等待其完成才能操作,最安全,同时效率最低(银行项目一般对安全有要求)
11.3事务回滚(了解)
<tx:advice id="txAdivce" transaction-manager="txManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" isolation="SERIALIZABLE" rollback-for="java.lang.Exception"/>
<tx:method name="update*" propagation="SUPPORTS"/>
<tx:method name="del*" propagation="NOT_SUPPORTED"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
在使用 throw
手动抛出异常时,建议加这个配置,否则不会回滚
<tx:method name="add*" propagation="REQUIRED" isolation="SERIALIZABLE" rollback-for="java.lang.Exception" no-rollback-for="java.lang.NullPointerException"/>
no-rollback-for 抛扫描异常时不会滚
12.常用注解
@Component
@Controller
@Service
@Repository
@Autowired spring提供的,默认按照byType注入
@Resource java提供的,默认按照byName注入,如果没有,按照byType注入
作用:自动按照类型完成依赖注入
@Value 获取properties中的值
@Pointcut 定义切点
@Aspect 定义切面
@Before 定义前置通知
@After 定义后置通知
@AfterReturing 定义返回通知
@Around 定义环绕通知
问到的数据具有完整性
脏读:事务a读取到事务b中未提交的数据,另一个事务数据可能改变了,此时A读取的数据与数据库不一致,此时读取的数据即为脏数据,这种读取到脏数据的现象称为脏读
不可重复读:事务a第一次读取数据,事务b对a读取的数据进行修改,事务a中再次读取的数据和之前读取不一致,主要发生在修改时(比如张三取钱时询问工作人员余额,得到反馈8万,此时张三老婆正在ATM取钱,取了5W,此时张三想取5W发现不够,两次读取结果不一样)
幻读:主要针对新增和删除,事务a按照特定条件查询,事务b新增了一条符合条件的数据,事务a查询的数据与数据库不一致,好像出现了幻觉,称为幻读
isolation属性主要解决的就是这些问题
取值可以是
default 数据库自己判断
read_uncommitted : 可以略去未提交的数据,可能出现脏读,不重复读,幻读,效率最高
read_committed : 只能读取其他事务中已提交的数据,防止脏读,可能出现不可重复读和幻读
repeatble_read : 读取的数据会被添加锁,防止其他事务修改此数据,可以防止不可重复读,脏读,可能出现幻读
SERIALIZABLE : 排队操作,对整个表加锁,一个事务在操作时,另一个事务需要等待其完成才能操作,最安全,同时效率最低(银行项目一般对安全有要求)
11.3事务回滚(了解)
<tx:advice id="txAdivce" transaction-manager="txManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" isolation="SERIALIZABLE" rollback-for="java.lang.Exception"/>
<tx:method name="update*" propagation="SUPPORTS"/>
<tx:method name="del*" propagation="NOT_SUPPORTED"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
在使用 throw
手动抛出异常时,建议加这个配置,否则不会回滚
<tx:method name="add*" propagation="REQUIRED" isolation="SERIALIZABLE" rollback-for="java.lang.Exception" no-rollback-for="java.lang.NullPointerException"/>
no-rollback-for 抛扫描异常时不会滚
12.常用注解
@Component
@Controller
@Service
@Repository
@Autowired spring提供的,默认按照byType注入
@Resource java提供的,默认按照byName注入,如果没有,按照byType注入
作用:自动按照类型完成依赖注入
@Value 获取properties中的值
@Pointcut 定义切点
@Aspect 定义切面
@Before 定义前置通知
@After 定义后置通知
@AfterReturing 定义返回通知
@Around 定义环绕通知
@AfterThrowing 定义异常通知