Spring初步学习记录
Spring学习
1 参考资料
2 Spring概述
2.1 Spring框架概述
-
Spring是一个轻量级的开源JavaEE框架
-
Spring可以解决企业应用开发的复杂性
-
Spring有两个核心部分:IoC和AOP
- IoC:控制反转,将创建对象过程交给Spring进行管理
- AOP:面向切面,不修改源代码的情况下进行功能增强
-
Spring的特点:
(1). 方便解耦,简化开发
(2). AOP编程的支持
(3). 方便程序的测试
(4). 方便和其他框架进行整合
(5). 方便进行事务
(6). 降低API开发难度
2.2 Spring5模块

2.3 Spring5入门案例
-
将Spring导入到项目
-
创建普通类
public class Test1 { public void helloSout() { System.out.println("Hello, Spring5!"); } } -
创建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="Test1"></bean> </beans> -
测试
package com.learning.create.testdemo; import com.learning.create.SpringCreateTest1; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test2 { public static void main(String[] args) { // 1.导入配置文件 ApplicationContext context1 = new ClassPathXmlApplicationContext("Test1.xml"); // 通过路径导入 ApplicationContext context2 = new FileSystemXmlApplicationContext("Test1.xml"); // 2.获取配置创建的对象 Test2 t = context.getBean("user", Test1); // 3.测试 System.out.println(t); t.helloSout(); } }
3 IoC(容器)
3.1 IoC底层原理
-
什么是IoC
- 控制反转(Inversion of Control,缩写为IoC),把对象创建和对象之间的调用过程,交给Spring进行管理
- 使用IoC的目的:为了降低耦合度
- 2.3 入门案例就是IoC实现
-
IoC底层原理
- xml解析、工厂设计模式、反射
- 实现过程

3.2 IoC接口(BeanFactory)
-
IoC思想基于IoC容器完成,IoC容器底层就是对象工厂
-
Spring提供IoC容器实现两种方式:(两个接口)
-
BeanFactory:IoC容器基本实现,是Spring内部的使用接口,不提供开发人员使用
- 加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
-
ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用
- 加载配置文件时候就会把在配置文件对象进行创建
-
-
Application接口有实现类
- ClassPathXmlApplicationContext:默认会去 classPath 路径下找。classPath 路径指的就是编译后的 classes 目录。如果是绝对路径,就需要加上 “file:” 前缀,不可缺省。
- FileSystemXmlApplicationContext:默认是去项目的路径下加载,可以是相对路径,也可以是绝对路径,若是绝对路径,“file:” 前缀可以缺省。
3.3 IoC操作Bean管理
-
什么是Bean管理
- 指的是两种操作
- Spring创建对象
- Spring注入属性
- 指的是两种操作
-
Bean管理操作有两种方式
(1). 基于xml配置文件方式实现
(2). 基于注解方式实现
3.3.1 基于xml方式
1 基于xml方式创建对象
<bean id="user" class="类全路径"></bean>
-
在Spring配置文件中,使用bean标签,标签里边添加对应属性,就可以实现对象的创建
-
bean标签有很多属性,常用的属性
- id:唯一标识
- class:类全路径(包类路径)
-
创建对象时,默认会使用无参构造器创建对象
2 基于xml方式注入属性
-
DI:依赖注入,就是注入属性
-
第一种方式:使用set方法进行注入
-
类中声明set方法
-
在xml文件配置属性注入
<!-- 使用set方法注入属性 --> <bean id="test" class="类全路径"> <!-- 使用property完成属性注入 name : 类里面属性名称 value : 向属性注入的值 --> <property name="属性名" value="属性值"></property> </bean>
-
-
第二种方式:使用有参构造器进行注入
-
在类中声明有有参构造器
-
在xml文件配置属性注入
<!-- 使用有参构造器注入属性 --> <bean id="test" class="类全路径"> <!-- 使用constructor-arg完成属性注入 name : 类里面属性名称 value : 向属性注入的值 index : 索引值,代表第i个属性 --> <constructor-arg name="属性名" value="属性值"></constructor-arg> </bean>
-
-
第三种方法:p名称空间注入(了解)
-
可以简化基于xml配置方式
-
底层还是基于set方法
<!-- 在beans标签中声明p空间 --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 使用p名称空间注入属性 --> <bean id="test" class="类全路径" p:属性名="属性值"></bean> </beans>
-
-
注入其他类型属性
- 字面量:默认值
- null
- 属性值中包含特殊符号
<bean id="test" class="类全路径"> <!-- 注入null --> <property name="属性名"> <null/> </property> <!-- 属性值中包含特殊符号,比如<Test> 1. 可以使用转义 2. 把带特殊符号内容写到CDATA,<![CDATA[内容]]> --> <!-- 使用转义 --> <property name="属性名" value="<Test>"></property> <!-- 把带特殊符号内容写到CDATA --> <property name="属性名"> <value><![CDATA[<Test>]]></value> </property> </bean> - 字面量:默认值
-
3 注入属性————外部Bean
举例:
- 创建两个类service类和dao类
- 在service中调dao类
// Service.java
package com.test.service;
public class Service {
public void show() {
System.out.println("show");
// 旧方法
// 1. 创建UserDaoImpl的对象
UserDao userDao = new UserDaoImpl();
userDao.update();
}
}
//UserDao接口
package com.test.dao;
public interface UserDao {
public void update();
}
//UserDao实现类
public class UserDaoImpl implements UserDao {
@Override
public void update() {
System.out.println("update");
}
}
- 在Spring配置文件中进行配置
采用注入属性的方法:
// Service.java 新方法
package com.test.service;
public class Service {
// 1. 创建UserDao属性
private UserDao userDao;
// 2. 创建set方法
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void show() {
System.out.println("show");
}
}
xml配置文件:
<!-- 进行属性注入 -->
<!-- 1. service和dao对象创建 -->
<bean id="userService" class="com.test.service.Service">
<!-- 注入对象
ref : 创建UserDaoImpl对象bean标签id值
-->
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.test.dao,UserDaoImpl"></bean>
4 注入属性————内部Bean
- 一对多关系:例如部门和员工
- 在实体类之间表示出一对多的关系
部门类:
//Dept.java
package com.test.bean;
public class Dept {
private String dname;
public void setDname(String dname) {
this.dname = dname;
}
}
员工类:
//Emp.java
package com.test.bean;
public class Emp {
private String ename;
private String gender;
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
public void setEname(String ename) {
this.ename = ename;
}
public void setGender(String gender) {
this.gender = gender;
}
}
- 在Spring配置文件中进行配置
<!-- 内部Bean -->
<bean id="emp" class="com.test.bean.Emp">
<!-- 设置普通属性 -->
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<!-- 设置对象属性 -->
<property name="dept">
<bean id="dept" class="com.test.bean.Dept">
<property name="dname" value="人事部"></property>
</bean>
</property>
</bean>
5 注入属性————级联赋值
- 以内部bean中例子为例
<!-- 级联赋值 -->
<!-- 第一种写法 -->
<bean id="emp" class="com.test.bean.Emp">
<!-- 设置普通属性 -->
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<!-- 级联赋值 -->
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.test.bean.Dept">
<property name="dname" value="人事部"></property>
</bean>
<!-- 第二种写法 -->
<!-- 需要在Emp.java中声明getDept()方法-->
<bean id="emp" class="com.test.bean.Emp">
<!-- 设置普通属性 -->
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<!-- 级联赋值 -->
<property name="dept" ref="dept"></property>
<property name="dept.dname" value="人事部"></property>
</bean>
<bean id="dept" class="com.test.bean.Dept">
<property name="dname" value="人事部"></property>
</bean>
6 注入集合属性
- 注入数组类型属性
- 注入List集合类型属性
- 注入Map集合类型属性
- 注入Set集合类型属性
- 集合类型注入对象属性
//Student.java
package com.test.spring;
public class Student {
// 1 数组类型属性
private String[] courses;
// 2 List集合类型属性
private List<String> list;
// 3 Map集合类型属性
private Map<String, String> maps;
// 4 Set集合类型属性
private Set<String> sets;
// 5 集合类型注入对象属性
private List<Course> courseList;
public void setCourses(String[] courses){
this.courses = courses;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
public void setSets(Set<String> sets) {
this.sets = sets;
}
public void setSets(List<Course> courseList) {
this.courseList = courseList;
}
}
//Course.java
package com.test.spring;
public class Course {
private String cname;
public void setCname(String cname) {
this.cname = cname;
}
}
- 配置文件配置
<!-- 集合类型属性注入 -->
<bean id="student" class="com.test.spring.Student">
<!-- 数组类型属性注入 -->
<property name="courses">
<array>
<value>java课程</value>
<value>数据库基础</value>
</array>
</property>
<!-- List类型属性注入 -->
<property name="list">
<list>
<value>张三</value>
</list>
</property>
<!-- Map类型属性注入 -->
<property name="maps">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>
<!-- Set类型属性注入 -->
<property name="sets">
<set>
<value>MySQL</value>
<value>Redis</value>
</set>
</property>
<!-- 集合类型注入对象属性 -->
<property name="courseList">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
<!-- 创建多个course对象 -->
<bean id="course1" class="com.test.springCourse">
<property name="cname" value="Spring5"></property>
</bean>
<bean id="course2" class="com.test.springCourse">
<property name="cname" value="MyBatis"></property>
</bean>
-
将集合注入部分提取出来
- 在Spring配置文件中引入名称空间util
- 使用util标签提取list集合类型属性注入
<!-- 以之前Student.java为例 --> <!-- 1 引入名称空间util --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!-- 使用util标签提取list集合类型属性注入 对象则使用ref标签,值用value --> <util:list id="list1"> <value>张三</value> <value>李四</value> </util:list> <bean id="student" class="com.test.spring.Student"> <property name="list" ref="list1"></property> </bean> </beans>
7 基于FactoryBean
-
Spring有两种类型bean,一种是普通bean,另一种是工厂bean。两者区别:普通bean在配置文件中定义的bean类型就是返回类型;工厂bean在配置文件中定义的bean类型可以和返回类型不同。
-
创建工厂bean
- 第一步:创建类,让这个类作为工厂bean,实现接口FactoryBean
- 第二步:实现接口里面的方法,在实现的方法中定义返回bean类型
//Example.java public class Example implements FactoryBean<String> { // 定义bean返回类型 @Override public String getObject() throws Exception { return "aaa"; } @Override ... }
8 bean的作用域
- 在Spring里面,设置创建bean实例是单实例还是多实例
- 在Spring里面,默认情况下,bean是单实例对象
- 如何设置单实例还是多实例
- 在Spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例
- scope属性值
- singleton,默认值,单实例对象
- prototype,多实例对象
- 两者区别:
- scope值是singleton时,加载Spring配置文件时候就会创建单实例对象
- scope值是prototype时,不是在加载Spring配置文件时候创建对象,在调用getBean方法时候创建多实例对象
- scope属性值
- 在Spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例
9 bean 的生命周期
-
生命周期:从对象创建到对象销毁的过程
-
具体过程:
- 创建:通过构造器创建bean实例
- 为bean的属性设置值和对其他bean的引用(调用set方法)
- 调用初始化方法(需要声明初始化方法,配置bean标签中的init-methode)
- 使用bean(对象获取)
- 销毁:容器关闭时,调用bean的销毁的方法(需要声明销毁的方法,配置bean标签中的destory-method)
-
bean的后置处理器
- 加上后置处理器后,bean的生命周期有七步:
1. 创建:通过构造器创建bean实例
2. 为bean的属性设置值和对其他bean的引用(调用set方法)
3. 把bean实例传递给bean后置处理器的方法(接口BeanPostProcessor中的postProcessBeforeInitialization方法)
4. 调用初始化方法(需要声明初始化方法,配置bean标签中的init-methode)
5. 把bean实例传递给bean后置处理器的方法(接口BeanPostProcessor中的postProcessAfterInitialization方法)
6. 使用bean(对象获取)
7. 销毁:容器关闭时,调用bean的销毁的方法(需要声明销毁的方法,配置bean标签中的destory-method)
- 加上后置处理器后,bean的生命周期有七步:
10 自动装配
-
根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入
-
根据属性名称注入
<!--实现自动装配 bean标签 : autowire,自动装配 autowire属性常用两个值: byName根据属性名称注入,注入值bean的id值和类属性名称要一样 byType根据属性类型注入, --> <bean id="emp" class="com.learning.spring.autowire.Emp" autowire="byName"></bean> <bean id="dpt" class="com.learning.spring.autowire.Dpt"></bean> -
根据属性类型注入
<!--实现自动装配 bean标签 : autowire,自动装配 autowire属性常用两个值: byName根据属性名称注入,注入值bean的id值和类属性名称要一样 byType根据属性类型注入,相同类型只能定义一个 --> <bean id="emp" class="com.learning.spring.autowire.Emp" autowire="byType"></bean> <bean id="dpt" class="com.learning.spring.autowire.Dpt"></bean>
-
11 外部属性文件
-
直接配置数据库信息
-
举例:置德鲁伊连接池
<!--直接配置连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/userDb"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> </bean>
-
-
引入外部属性文件配置数据库连接池
-
创建一个外部属性文件,properties格式文件,写数据库信息
jdbc.properties:prop.driverClass=com.mysql.jdbc.Driver prop.url=jdbc:mysql://localhost:3306/userDb prop.userName=root prop.password=root- 把外部的properties属性文件引入到Spring配置文件中(引入context名称空间)
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" 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 http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--引入外部属性文件--> <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> <!--配置连接池--> <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> </beans>
-
3.3.2 基于注解方式
1 什么是注解
- 注解是代码特殊标记,格式:@注解名称(属性名称=属性值[,属性名称=属性值,...])
- 使用注解,注解作用再类上面,方法上面,属性上面
- 目的:简化xml配置
2 Spring针对Bean管理中创建对象提供注解
下面四个注解功能是一样的,都可以用来创建bean实例:
- @Componret : 建议用在bean层
- @Service : 建议用在service层
- @Controller : 建议用在controller层
- @Repository : 建议用在dao层
3 基于注解方式实现对象创建
- 第一步:引入依赖(引入spring-aop jar包)
- 第二步:开启组件扫描
<!-- 先要引入context名称空间 -->
<!--开启组件扫描
1 如果扫描多个包,多个包使用逗号隔开
2 扫描包上层目录
-->
<context:component-scan base-package="com.atguigu"></context:component-scan>
- 第三步:创建类,在类上面添加创建对象注解
//UserService.java
//在注解里面value属性值可以省略不写
//默认值是类名称,首字母小写
//UserService -> userService
@Component(value = "userService") //<bean id="userService" class=""/>
public class UserService {
public void add() {
System.out.println("add...");
}
}
4 开启组件扫描细节配置
<!-- 示例1
use-defaultfilters="false"表示现在不适用默认filters,自己配置filter
context:include-filter:设置扫描哪些内容
-->
<context:component-scan base-package="com.atguigu" use-defaultfilters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/><!--代表只扫描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"/><!--表示Controller注解的类之外一切都进行扫描-->
</context:component-scan>
5 实现属性注入
-
@Autowired:根据属性类型进行自动装配
-
第一步 把service和dao对象创建,在service和dao类添加创建对象注解
-
第二步 在service注入dao对象,在service类添加dao类型属性,在属性上面使用注解
//UserService.java @Service public class UserService { // 1.定义dao类型属性 // 2.不需要添加set方法 // 3.添加注入属性注解 @Autowired private UserDao userDao; public void add() { System.out.println("Service add..."); userDao.add(); } } //UserDao实现类 UserDaoImpl.java @Repository public class UserDaoImpl implements UserDao{ @Override public void add() { System.out.println("add..."); } }
-
-
@Qualifier:根据属性名称进行注入,@Qualifier注解的使用,和上面@Autowired一起使用
@Autowired
//根据名称进行注入(目的在于区别同一接口下有多个实现类,根据类型就无法选择,从而出错!)
@Qualifier(value = "userDaoImpl1")
private UserDao userDao;
- @Resource:可以根据类型注入,可以根据名称注入(它属于javax包下的注解,不推荐使用!)
//@Resource //根据类型注入
@Resource(name = "userDaoImpl1") //根据名称注入
private UserDao userDao;
- @Value:注入普通类型属性
@Value(value = "abc")
private String name;
6 完全注解开发
- 创建配置类,替代xml配置文件
@Configuration // 作为配置类,替代xml配置文件
@ComponentScan(basePackages = {"com.learning.spring"})
public class SpringConfig {
}
- 编写测试类
@Test
public void testService2() {
// 加载配置类
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}
4 AOP
4.1 AOP基本概念
- 面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得 业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
- 通俗描述:不通过修改源代码方式,在主干功能里面添加新功能
- 使用登录例子说明 AOP

4.2 AOP底层原理
- AOP 底层使用动态代理 ,动态代理有两种情况:
- 有接口情况,使用JDK动态代理:创建接口实现类代理对象,增强类的方法

- 没有接口的情况,使用CGLIB动态代理:创建子类的代理对象,增强类的方法

- 有接口情况,使用JDK动态代理:创建接口实现类代理对象,增强类的方法
4.2.1 AOP底层原理——JDK动态代理实现
-
使用JDK动态代理,使用Proxy类里面的方法来创建对象
- 调用newProxyInstance方法
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)- 方法有三个参数:
- 第一参数,类加载器
- 第二参数,增强方法所在的类,这个类实现的接口,支持多个接口
- 第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分
-
编写JDK动态代理代码
- 第一步:创建接口,定义方法
public interface UserDao { public int add(int a, int b); public String update(String id); }- 第二步:创建接口实现类,实现方法
public class UserDaoImpl implements UserDao{ @Override public int add(int a, int b) { return a + b; } @Override public String update(String id) { return id; } }- 第三步:使用Proxy类创建接口代理对象
public class JDKProxy { public static void main(String[] args) { //创建接口代理类 Class[] interfaces = {UserDao.class}; UserDao dao = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(new UserDaoImpl())); int result = dao.add(1 ,2); System.out.println(result); } } class UserDaoProxy implements InvocationHandler { // 1. 把创建的是谁的代理对象,把谁传递过来 // 有参构造传递 private Object obj; public UserDaoProxy(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; } }
4.3 AOP术语
-
连接点:类里面哪些方法可以被增强,这些方法称为连接点
-
切入点:实际被真正增强的方法称为切入点
-
通知(增强):实际增强的逻辑部分称为通知,且分为以下五种类型:
- 前置通知:方法之前执行增强部分
- 后置通知:方法之后执行增强部分
- 环绕通知:方法前后执行增强部分
- 异常通知
- 最终通知:类似finally
-
切面:把通知应用到切入点过程
4.4 AOP操作
4.4.1 准备工作
-
Spring框架一般都是基于AspectJ实现AOP操作
- 什么是AspectJ:AspectJ不是Spring组成部分,独立AOP框架,一般把 AspectJ和Spirng框架一起使用,进行AOP操作
-
基于AspectJ实现AOP操作
- 基于xml配置文件实现
- 基于注解方式实现(使用)
-
引入相关jar包
-
切入点表达式,如下:
//(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
//(2)语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]) ) 其中权限修饰符可以省略,但返回类型不能省略(*匹配所有返回类型)
//(3)例子如下:
//例 1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强
execution(* com.atguigu.dao.BookDao.add(..))
//例 2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强
execution(* com.atguigu.dao.BookDao.* (..))
//例 3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强
execution(* com.atguigu.dao.*.* (..))
4.4.2 AspectJ注解
-
创建类,在类里边定义方法
// 被增强的类 public class User { public void add() { System.out.println("add..."); } } -
创建增强类(编写增强逻辑)
- 在增强类中创建方法,让不同方法代表不同通知类型
// 增强的类 public class UserProxy { // 前置通知 public void before() { System.out.println("before..."); } } -
进行通知的配置
1、在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:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--开启注解扫描--> <context:component-scan base-package="com.atguigu"></context:component-scan> <!-- 开启生成代理对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>或者用配置类
@Configuration @ComponentScan(basepackage = {"com.atguigu"}) @EnableAspectJAutoProxy(proxyTargetClass = true) //不写,默认是true public class ConfigAop { }2、使用注解创建User和UserProxy对象,在增强类上面添加注解@Aspect
// 被增强的类 @Component public class User @Component @Aspect public class UserProxy3、配置不同类型的通知
(1)在增强类的里边,在作为通知方法上面添加通过类型注解,使用切入点表达式// 增强的类 @Component @Aspect public class UserProxy { // 相同切入点抽取 @Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") public void pointdemo() { } // 前置通知 // @Before注解表示作为前置通知 @Before(value = "pointdemo()") // 相同切入点使用 public void before() { System.out.println("before..."); } //后置通知(返回通知) @AfterReturning(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") public void afterReturning() { System.out.println("afterReturning........."); } //最终通知 @After(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") public void after() { System.out.println("after........."); } //异常通知 @AfterThrowing(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") public void afterThrowing() { System.out.println("afterThrowing........."); } //环绕通知 @Around(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕之前........."); //被增强的方法执行 proceedingJoinPoint.proceed(); System.out.println("环绕之后........."); } } -
有多个增强类对同一个方法进行增强,设置增强类优先级
//(1)在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高
@Component
@Aspect
@Order(1)
public class PersonProxy{ }
4.4.3 AspectJ配置文件
<!--1、创建两个类,增强类和被增强类,创建方法(同上一样)-->
<!--2、在 spring 配置文件中创建两个类对象-->
<!--创建对象-->
<bean id="book" class="com.atguigu.spring5.aopxml.Book"></bean>
<bean id="bookProxy" class="com.atguigu.spring5.aopxml.BookProxy"></bean>
<!--3、在 spring 配置文件中配置切入点-->
<!--配置 aop 增强-->
<aop:config>
<!--切入点-->
<aop:pointcut id="p" expression="execution(* com.atguigu.spring5.aopxml.Book.buy(..))"/>
<!--配置切面-->
<aop:aspect ref="bookProxy">
<!--增强作用在具体的方法上-->
<aop:before method="before" pointcut-ref="p"/>
</aop:aspect>
</aop:config>
5 JdbcTemplate
5.1 JdbcTemplate概念及使用
- Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作

浙公网安备 33010602011771号