关键词:
文章目录
前言
上回为各位分享了《六万字最全总结Java数据库编程MyBatis》没有学过的同学,建议先学MyBatis,这次在此基础上我们来学习经典框架之Spring!
❤️爆肝六万字最全总结Java数据库编程MyBatis(建议收藏)
相关资料:
文档:02_Spring配置文件和配置类
1. Spring概述
1.1 介绍
Spring框架是企业使用最多的框架,没有之一。Spring是一站式框架,称之为一站式框架的原因是Spring可以整合其他框架。
要学习Spring的内容如下:
l Spring IoC:对象工厂及依赖注入;
l Spring AOP:面向切面编程技术,为Spring事务管理打下基础。
l Spring Transaction management:Spring事务管理。
l Spring Web MVC(不包含在本课程内,后面单独学习):简称Spring MVC框架,用来简化JavaWEB开发,当使用Spring MVC框架后,就不用再编写Servlet了。也就不再需要itcast-tools工具中BaseServlet类了。
l Spring与其他框架整合:因为我们只学习过MyBatis框架,所以当前我们只学习Spring整合MyBatis框架。
2. IoC入门
2.1 什么是IoC
Spring IoC的核心如下:
l 工厂负责对象生命周期的管理;(spring管理创建与销毁)
l 对象的依赖由工厂完成注入。(spring维护对象间关系)
Spring提出了对象工厂的概念,由Spring工厂来管理对象的生命周期。所谓对象生命周期指的是从对象的创建一直到对象的销毁都由Spring来管理。我们无需再自己new对象,而是从Spring工厂中获取需要的对象。甚至对象的依赖也由工厂来注入,无需手动注入依赖。
Spring工厂是ApplicationContext接口,通常我们使用的是AnnotationConfigApplicationContext类。其中Spring工厂内部是通过Map类型来维护的。
key | value |
---|---|
“userDao1” | UserDao实例 |
“userService1” | UserService实例 |
… | … |
当我们需要获取工厂中的实例时,只需要调用工厂的getBean(“id”)即可。
@Test
public void test3()
AnnotationConfigApplicationContext context = ...
UserDao userDao = (UserDao) context.getBean("userDao1");
...
2.2 IoC入门案例1(基础案例)
入门案例1 使用IOC的方式创建UserDao对象 调用查询所有方法
思路:
- 目标类上加@Component
创建UserDao类, 书写方法 findAll ,在类上添加注解@component(”名字”),用来告知spring可以通过指定名字来创建该UserDao对象
- 配置类添加@Configuration 和 @ComponentScan
创建配置类 [SpringConfiguration,类上添加@Configuration注解和@ComponentScan注解.[(作用是用来告知Spring该类是配置类,并要扫描的包有哪些)]
- 测试类通过ApplicationContext的getBean(“名字”)获取对象
案例步骤如下:
l 配置类(SpringConfiguration)
l UserDao类
l UserDaoTest类
2.2.1 下载Spring
官网:http://spring.io/
下载地址:
http://repo.springsource.org/libs-release-local/org/springframework/spring
解压:(Spring目录结构:)
docs :API和开发规范.
libs :jar包和源码.
schema :约束.
我们上课使用的maven,使用老师发的pom文件即可.
Pom文件也可以从本文档结尾的附录的pom01-Spring入门拷贝
2.2.2 配置类(SpringConfiguration)
任何Spring项目都建议创建配置类,它提供了Spring工厂最基本的配置信息。本案例中该类没有任何内容,只需要添加两个注解。
SpringConfiguration.java
package com.czxy.comfig;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ComponentScan(basePackages = "com.czxy.dao")
@Configuration
public class SpringConfiguration
l 其中@Configuration注解告知Spring当前类是一个配置类;
l 其中@componentScan注解告知Spring要扫描的包,Spring会扫描并加载指定包下所有类中的注解。
2.2.3 UserDao.java
我们需要在编写UserDao类,同时希望Spring去创建该类实例并添加到工厂中。这需要在类上添加@Component注解,同时指定实例的id。Spring会扫描到UserDao类上的@Component注解。
UserDao.java
package com.czxy.dao;
import org.springframework.stereotype.Component;
@Component("ud")
public class UserDao
public void findAll()
System.out.println("查询所有");
2.2.4 UserDaoTest测试类
在测试类中我们需要先创建工厂对象,然后从工厂对象中获取UserDao对象实例。
UserDaoTest.java
package com.czxy.test;
import com.czxy.comfig.SpringConfiguration;
import com.czxy.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestA
public static void main(String[] args)
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
UserDao userDao = (UserDao) applicationContext.getBean("ud");// new UserDao();
userDao.findAll();
2.3 IoC入门案例2(依赖注入)
入门案例2中我们需要创建UserService类,但我们知道UserServce一定会依赖UserDao类。然后我们让Spring工厂帮助我们完成依赖注入。
步骤如下:
l 定义UserService类并添加@Component注解;
l 在UserService类中添加private UserDao userDao依赖;
l 在userDao成员上添加@Resource注解指定依赖。
SpringConfiguration.java
package com.czxy.comfig;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ComponentScan(basePackages = "com.czxy.dao","com.czxy.service")
@Configuration
public class SpringConfiguration
UserService.java
package com.czxy.service;
import com.czxy.dao.UserDao;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component("us")
public class UserService
@Resource(name = "ud")
private UserDao userDao ;//= new UserDao();
public void findAllUsers()
System.out.println("开始查找");
userDao.findAll();
System.out.println("查找结束");
测试类
@Test
public void test02()
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
UserService userService = (UserService) applicationContext.getBean("us");
userService.findAllUsers();
测试结果:
2.4 IoC入门案例3(面向接口编程)
入门案例3提供dao的接口和实现类、提供service的接口和实现类,程序之间使用接口,将所有实现类交予spring管理,完成程序间的解耦。
l 步骤如下
n 编写UserDao接口和实现类,并在实现类中添加@Component注解
n 编写UserService接口和实现类,并在实现类中添加@Component注解
n 在userDao成员变量中添加@Resource注解,注入dao的实现类。
n 编写配置类
n 编程测试类
l dao接口和实现类
public interface UserDao
public void findAll();
@Component("userDaoImpl")
public class UserDaoImplA implements UserDao
public void findAll()
System.out.println("A方式 查询所有");
l service接口和实现类
public interface UserService
public void findAllUsers();
@Component("userServiceImpl")
public class UserServiceImplA implements UserService
@Resource(name = "userDaoImpl")
private UserDao userDao ;//= new UserDao();
public void findAllUsers()
System.out.println("开始查找");
userDao.findAll();
System.out.println("查找结束");
l 配置类 不变
@ComponentScan(basePackages = "com.czxy.dao","com.czxy.service")
@Configuration
public class SpringConfiguration
l 测试类
@Test
@Test
public void test03()
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
UserService userService = (UserService) applicationContext.getBean("userServiceImpl");
userService.findAllUsers();
测试结果:
2.5 IoC入门案例4(整合JUnit4)
l 修改测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=SpringConfigruation.class)
public class UserDaoTest
@Resource(name="userService1")
private UserService userService;
@Test
public void testFindAll()
userService.findAll();
3. IoC详解
3.1 Bean的创建
前面已经学习了创建Bean的注解@Component,Spring还提供了一些衍生注解。
注解 | 描述 |
---|---|
@Component | 将修饰的资源交予spring管理。value属性:为资源命名(唯一标识) |
@Controller | 衍生注解,与@Component作用和属性相同。特用于修饰表示层的资源。 |
@Service | 衍生注解,与@Component作用和属性相同。特用于修饰业务逻辑层的资源。 |
@Repository | 衍生注解,与@Component作用和属性相同。特用于修饰数据访问层的资源。 |
示例: 分别使用不同名字的注解来设置响应的类
@Repository("userDao1")
public class UserDaoImpl implements UserDao
public void findAll()
System.out.println("入门案例");
@Service("userService1")
public class UserServiceImpl implements UserService
@Resource(name="userDao1")
private UserDao userDao;
public void findAll()
System.out.println("user service ...");
userDao.findAll();
l 以上4个注解修饰的类,我们通常称为注册bean。目的是将某类的实例对象,添加到spring容器中。
3.2 依赖注入(DI)
注解 | 描述 | 修饰位置 |
---|---|---|
@Resource(name=”…”) | 按照指定名称注入对象 | 字段、setter方法 |
@ Resource | 按照类型注入对象 | 字段、setter方法 |
@Value | 注入简单值 | 字段、setter方法、参数 |
@PropertySource | 加载properties配置文件 | 类 |
3.2.1 按照名称注入
示例: 按照名称来注入userDao对象
dao
@Repository("userDao1")
public class UserDaoImpl implements UserDao
public void findAll()
System.out.println("入门案例");
service
@Service("userService1")
public class UserServiceImpl implements UserService
@Resource(name="userDao1")
private UserDao userDao;
public void findAll()
System.out.println("user service ...");
userDao.findAll();
3.2.2 按照类型注入
示例: 分别创建dao ,service ,和测试类,按照类型注入对应的对象
dao
@Repository
public class UserDaoImpl implements UserDao
public void findAll()
System.out.println("入门案例");
service
@Service
public class UserServiceImpl implements UserService
@Resource
private UserDao userDao;
public void findAll()
System.out.println("user service ...");
userDao.findAll();
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=SpringConfigruation.class)
public class UserDaoTest
@Resource
private UserService userService;
@Test
public void testFindAll()
userService.findAll();
3.2.3 普通数据注入
示例:字符串类型的成员变量和方法参数注入数据.
固定值注入
public class SpringConfigruation
@Value("com.mysql.jdbc.Driver")
private String driver;
@Value("jdbc:mysql://127.0.0.1:3306/crm_ssm_v1_0")
public void setUrl(String url)
System.out.println("字段:" + driver);
System.out.println("方法:" + url);
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=SpringConfigruation.class)
public class UserDaoTest
@Test
public void testFindAll() throws SQLException
4 properties数据注入
需求: 把properties文件中的数据读取出来,在测试类中展示
总体思路:
使用@PropertySource加载properties配置文件,“classpath:”固定前缀,表示从类路径下加载配置文件。
@Value($jdbc.driver) 获得配置文件中指定key的内容
默认:将整个表达式进行注入,及 driver变量的值是 $jdbc.driver
固定代码:必须配置PropertySourcesPlaceholderConfigurer实例。
项目结构如下:
jdbc.properties配置文件:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/test1
jdbc.username=root
jdbc.password=1234
配置类 添加内容
package com.czxy.demo02;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
@Configuration
@PropertySource("classpath:db.properties")
public class SpringConfig02
// 在4.2.4版本读取properties必须写,必须要写的固定格式
@Bean
public static PropertySourcesPlaceholderConfigurer create()
return new PropertySourcesPlaceholderConfigurer();
测试类:
package com.czxy.demo02;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig02.class)
public class TestB
@Value("$jdbc.driver")
private String driverClassName;
@Value("$jdbc.url")
private String url;
@Test
public void test01()
System.out.println("driverClassName="+driverClassName);
System.out.println("url="+url);
测试结果:正常获取数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SIWE7Gtr-1633402543916)(C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\ksohtml\\wps7DBD.tmp.jpg)]
1.1 @Bean(工厂Bean)
把别人创建的类,交给IOC管理可以使用方法配合注解@Bean的方式实现.
通过@Component等注解,将我们自己编写的对象配置到spring容器中。
通过@Resource等注解,将我们自己编写的对象之间的关系配置到spring容器中。
实际开发中,我们经常会遇到某些类不是我们写的,此时我们希望通过IOC对这种类进行管理,我们就没法办在这个类上加@Component等注解了. 这个时候可以创建一个方法在方法上使用@Bean来实现对这些类对象的管理
3.2.5 基本使用:类型注入
@Bean用于修饰方法 ,将方法创建的对象添加到spring容器
需求: 假设UserDao不是我们写的类,无法使用@Component注解,
创建一个方法用于获取UserDao对象
准备如下几个类
UserDao:
package com.czxy.demo03;
public class UserDao
public void findAll()
System.out.println("查询所有 ");
SpringConfig03:
package com.czxy.demo03;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig03
@Bean
public UserDao getUserDao()
return new UserDao();
测试类:
package com.czxy.demo03;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig03.class)
public class TestC
@Resource
private UserDao userDao;
@Test
public void test01()
userDao.findAll();
测试结果:
3.2.6 基本使用:指定名称注入
上面例子中,在方法上只是书写了一个@Bean.并没有给期产生的对象命名如果想命名可以通过如下方式.
@Bean(name=”名字”) 可以为当前对象设置一个名称,如果没有使用name设置名称,默认名为“ 方法名 ”。
需求:
UserDao是个接口,有俩实现类UserDaoImplA和UserDaoImplB, 这三个类假设我们都不能修改.
现在想获取这俩实现类的对象,交给IOC管理. 设计完成该例子.
项目结构如下:
UserDao接口:
package com.czxy.demo04;
public interface UserDao
public void findAll();
UserDaoImplA实现类:
package com.czxy.demo04;
public class UserDaoImplA implements UserDao
@Override
public void findAll()
System.out.println("A 方式实现查询所有用户 ");
UserDaoImplB实现类:
package com.czxy.demo04;
public class UserDaoImplB implements UserDao
@Override
public void findAll()
System.out.println("B 方式实现查询所有用户 ");
配置类:
package com.czxy.demo04;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig04
@Bean(name ="userDaoImplA" )
public UserDao getUserDaoA()
return new UserDaoImplA();
@Bean(name ="userDaoImplB" )
public UserDao getUserDaoB()
return new UserDaoImplB();
测试类:
package com.czxy.demo04;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig04.class)
public class TestD
@Resource(name = "userDaoImplB")
private UserDao userDao;
@Test
public void test01()
userDao.findAll();
测试结果:
userDaoImplB对应:
userDaoImplA对应:
3.2.7 依赖注入:引用类型
当某一个方法的参数是一个被IOC管理的对象时,可以通过@Bean的方式,自动注入该对象.
如UserDao对象被IOC管理了. 那么 若有方法 形如testXXX(UserDao userDao) 则可以在方法上添加@Bean,来自动注入UserDao对象.
示例1:
把UserDao交给IOC
在配置类中书写一个方法show(UserDao userDao),完成自动注入,在测试类中进行测试.
代码详情:
UserDao
package com.czxy.demo06;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao
public void findAll()
System.out.println("查询所有");
配置类:SpringConfig06
package com.czxy.demo06;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import javax.annotation.Resource;
@Configuration
@ComponentScan(basePackages = "com.czxy.demo06")
public class SpringConfig06
@Bean
public String show(UserDao userDao)
System.out.println("完成自动注入:"+userDao);
//测试调用userDao方法
userDao.findAll();
return null;
测试类:
package com.czxy.demo06;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig06.class)
public class TestA1
@Test
public void test02()
//无需书写任何代码, 单纯执行
//该方法就会看到自动注入UserDao
测试结果:
可以看到 完成了自动注入.
示例2:
把UserDao对象存放到spring容器中, 然后再UserService方法中要使用UserDao,此时可以直接把UserDao当做参数传递到方法中
`
配置类:
package com.czxy.demo02.config;
import com.czxy.demo02.dao.UserDao;
import com.czxy.demo02.dao.UserDaoImpl;
import com.czxy.demo02.service.UserService;
import com.czxy.demo02.service.UserServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "com.czxy.demo02")
public class SpringConfiguration
@Bean
public UserDao getUserDao()
return new UserDaoImpl();
@Bean
public UserService getUserService(UserDao userDao)
System.out.println(userDao);
return new UserServiceImpl();
测试类
package com.czxy.demo02.test;
import com.czxy.demo02.config.SpringConfiguration;
import com.czxy.demo02.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class TestA
@Resource
public UserService userService;
@Test
public void test01()
System.out.println(userService);
测试结果:
3.2.8 依赖注入:简单类型
需求: 把properties文件中的字符串 以简单类型的方式添加到参数中 打印对应的值.
l 配置类
相应代码:
@PropertySource("classpath:db.properties")
public class SpringConfiguration2
@Bean
public static PropertySourcesPlaceholderConfigurer create()
return new PropertySourcesPlaceholderConfigurer();
@Bean
public UserService createUserService(@Value("$jdbc.username") String name, @Value("$jdbc.password") String pwd)
System.out.println("name = "+name+" pwd ="+pwd);
return new UserServiceImpl();
l 测试类
代码:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration2.class)
public class TestB
@Resource
private UserService userService;
@Test
public void test01()
System.out.println(userService);
测试结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3KBzWRNK-1633402543928)(C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\ksohtml\\wps7DD8.tmp.jpg)]
1.1 Bean的作用域
通过@Scope可以Bean的作用域,也就是通知spring是否每次都创建新对象。
注解 | 描述 | 取值 |
---|---|---|
@Scope | 用于设置Bean的作用域 | singleton :默认值,单例的.prototype :多例的. |
单例模式: 整个IOC容器中只有该实体类的一个对象
多例模式: 整个IOC容器中该实体类有多个对象
示例:
搞一个User类,在配置类中设置单例模式和多例模式,创建两个对象观察效果.
配置类:
测试类:
单例模式结果: 地址编号相同,说明是用的同一个对象
保持测试类不变,只更改为多例模式
测试结果:打印的两个地址编号不同,说明IOC容器中有多个对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WWrI1INl-1633402543932)(C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\ksohtml\\wps7DEF.tmp.jpg)]
l 其他取值(了解)
-
request :WEB项目中,Spring创建一个Bean的对象,将对象存入到request域中.
-
session :WEB项目中,Spring创建一个Bean的对象,将对象存入到session域中.
-
globalSession :WEB项目中,应用在Portlet环境.如果没有Portlet环境那么globalSession相当于session
3.3 生命周期
生命周期指 单实例 对象由创建到销毁的整个过程。
此处,主要研究初始化方法和销毁方法。
3.3.1 实例Bean
实例Bean同时2个注解,来控制类中那个方法初始化方法,那个方法是销毁方法。
注解 | 描述 |
---|---|
@PostConstruct | 初始化方法,项目启动时执行,只会被调用一次。 |
@PreDestroy | 销毁方法,项目关闭时执行,只会被调用一次。 |
实例Dog
@Component
public class Dog
@PostConstruct
public void init()
System.out.println("狗 初始化");
public void eat()
System.out.println("狗 吃吃吃..");
@PreDestroy
public void destory()
System.out.println("狗 销毁 ");
配置类
@ComponentScan(basePackages="com.czxy.domain")
public class SpringConfigruation
测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class TestC
@Resource
private Dog dog;
@Test
public void test01()
dog.eat();
测试结果 :
3.3.2 工厂Bean
工厂Bean通过@Bean的2个属性完 成初始化和销毁方法的配置。
initMethod:配置初始化方法
destroyMethod:配置销毁方法
实体类:
public class Cat
public void init()
System.out.println("猫 初始化");
public void eat()
System.out.println("猫 吃吃吃..");
public void destory()
System.out.println("猫 销毁 ");
配置类
@Configuration
@ComponentScan(basePackages = "com.czxy.demo02")
public class SpringConfiguration
@Bean(initMethod = "init" ,destroyMethod = "destory")
public Cat getCat()
return new Cat();
测试类:
@Resource
private Cat cat;
@Test
public void test02()
cat.eat();
测试结果:
4. AOP
4.1 AOP概述
4.1.1 什么是AOP
AOP:全称是Aspect Oriented Programming即:面向切面编程。
面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用代理的技术,在不修改原来代码的基础上,对已有方法进行增强。
4.1.2 快速入门1
需求:
User类中有方法eat . 现在在不修改eat方法的前提下,对eat进行增强. 增强的内容是,在执行eat之前,先执行 沐浴更衣 这个动作.
实现思路:
\\1. 搭建基本的测试 可以在测试类中执行eat方法
\\2. 创建切面类,指明对eat方法进行增强;
具体代码如下: 在书写代码之前记得在pom文件添加spring相关的依赖.
User类
@Component
public class User
public void eat()
System.out.println("吃吃吃");
配置类:
@Configuration //设置为 配置类
@ComponentScan(basePackages = "com.czxy.demo01") // 设置要扫描的包
@EnableAspectJAutoProxy // 设置 开启切面
public class SpringConfig01
切面类:
@Component
@Aspect
public class MyAspect01
@Before("execution(public void com.czxy.demo01.User.eat())")
public void bf01()
System.out.println("沐浴更衣 ");
测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes =SpringConfig01.class)
public class TestA
@Resource
private User user;
@Test
public void test01()
user.eat();
执行结果:
4.1.3 AOP作用和优势
l 作用:
\\4. 在程序运行期间,不修改源码对已有方法进行增强。
l 优势:
\\5. 减少重复代码
\\6. 提高开发效率
\\7. 维护方便
4.1.4 快速入门2
需求: 使用AOP 对UserService接口的两个方法进行增强. 在方法执行之前,开启事务,在方法执行之后关闭事务.
项目结构:
具体代码:
Pom中需要添加aop相关的依赖
UserService接口: 接口中提供两个方法
public interface UserService
public void addUser();
public void delUser();
实现类UserServiceImpl
@Service
public class UserServiceImpl implements UserService
@Override
public void addUser()
System.out.println("添加用户 ");
@Override
public void delUser()
System.out.println("删除用户");
配置类:
@Configuration
@ComponentScan(basePackages = "com.czxy.demo02")
@EnableAspectJAutoProxy
public class SpringConfiguration2
切面类MyAspect02:
@Component
@Aspect
public class MyAspact02
@Before("execution(public void com.czxy.demo02.UserService.*())")
public void bf()
System.out.println("开启事务");
@After("execution(public void com.czxy.demo02.UserService.*())")
public void af()
System.out.println("关闭事务");
测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration2.class)
public class TestB
@Resource
private UserService userService;
@Test
public void test01()
userService.addUser();
System.out.println("----------");
userService.delUser();
测试结果:
4.1.5 快速入门3
需求: 使用AOP 对UserService和BookService接口的方法进行增强.
4.1.6 AOP实现方法
Spring AOP 主要通过2种代理技术来实现:动态代理、CGLIB
动态代理:用于对接口+实现类情况进行代理。
@EnableAspectJAutoProxy(proxyTargetClass = false )
CGLIB:用于对仅有类情况进行代理。
@EnableAspectJAutoProxy(proxyTargetClass = true )
4.2 相关AOP术语
Target( *目标对象 *):
代理的目标对象。通俗点讲:你需要增强的类,这个类就是目标对象
例如:UserServiceImpl
Joinpoint( *连接点 *):
所谓连接点是指可能被增强的位置。在spring中,AOP是对方法进行增强,这个位置/时机可以是方法前或者方法后,或者出异常的时候。
例如:addUser()方法执行之前的位置 或者 addUser()方法执行之后的位置 或者 AddUser出异常的时候
Pointcut( *切入点 *):
所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。通俗讲: 确定了在哪个位置进行增强
例如:@Before(“execution(public void com.czxy.demo02.UserService.addUser())”)
Advice( *通知 */ *增强 *): 具体要干的事情
所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。
通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
例如:bf()、af()
Aspect( *切面 *):
是切入点和通知的结合。
例如:MyAspect类
Proxy *(代理) *:
一个类被AOP增强后,就产生一个结果代理类。
4.3 相关注解
注解 | 描述 | |
---|---|---|
@Aspect | 把当前类声明成切面类 | |
@Before | 把当前方法看成是前置通知 | |
@AfterReturning | 把当前方法看成是后置通知。 | |
@AfterThrowing | 把当前方法看成是异常通知 | |
@After | 把当前方法看成是最终通知 | |
@Around | 把当前方法看成是环绕通知 | |
@Pointcut | 指定切入点表达式 |
4.3.1 切入点表达式
execution:
匹配方法的执行(常用)
execution(表达式)
表达式语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))
写法说明:
全匹配方式:
public void com.itheima.service.impl.CustomerServiceImpl.saveCustomer()
访问修饰符可以省略
void com.itheima.service.impl.CustomerServiceImpl.saveCustomer()
返回值可以使用*号,表示任意返回值
* com.itheima.service.impl.CustomerServiceImpl.saveCustomer()
包名可以使用*号,表示任意包,但是有几级包,需要写几个*
* *.*.*.*.CustomerServiceImpl.saveCustomer()
使用..来表示当前包,及其子包
* com..CustomerServiceImpl.saveCustomer()
类名可以使用*号,表示任意类
* com..*.saveCustomer()
方法名可以使用*号,表示任意方法
* com..*.*()
参数列表可以使用*,表示参数可以是任意数据类型,但是必须有参数
* com..*.*(*)
参数列表可以使用..表示有无参数均可,有参数可以是任意类型
* com..*.*(..)
全通配方式:
* *..*.*(..)
4.3.2 通知方法
l 方式1:没有参数形式
@Before("execution(public void com.czxy.demo01.User.eat())")
public void bf01()
System.out.println("洗手 ");
执行效果:
l 方式2:获得参数JoinPoint,从而获得目标类,目标方法等信息
@Before("execution(public void com.czxy.demo01.User.eat())")
public void bf01(JoinPoint jp)
System.out.println("洗手 ");
System.out.println("目标类:"+jp.getTarget());//获取目标类
System.out.println("切入点:"+jp.getSignature());//获取切入点
执行效果:
l 方式3:环绕通知获得参数ProceedingJoinPoint,对目标方法的执行进行控制。
@Around("execution(public void com.czxy.demo01.User.eat())")
public void ar(ProceedingJoinPoint jp) throws Throwable
System.out.println("洗手 ");
jp.proceed();//执行 eat方法
System.out.println("擦嘴");
执行效果:
4.3.3 抽取公共 切入点
使用@PointCut可以将公共的切入点进行抽取,一般都声明在私有方法上。
在通知注解使用,通过方法名引用。
@Pointcut("execution(* com.czxy.service..*.*(..))")
private void myPointcut()
@Before("myPointcut()")
public void bf(JoinPoint joinPoint)
System.out.println("前置..." + joinPoint.getTarget());
System.out.println("前置..." + joinPoint.getSignature().getName());
@AfterReturning("myPointcut()")
public void af()
System.out.println("后置...");
4.4 完整通知演示
4.4.1 AOP编程
l 编写需要对目标类,增量的类和方法(可以复制)
@Pointcut("execution(* com.czxy.service..*.*(..))")
private void myPointcut()
@Before("myPointcut()")
public void bf(JoinPoint joinPoint)
System.out.println("前置..." + joinPoint.getTarget());
System.out.println("前置..." + joinPoint.getSignature().getName());
@AfterReturning("myPointcut()")
public void af()
System.out.println("后置...");
l 测试
4.4.2 目标接口和类
接口
public interface UserService
public void saveUser();
public String updateUser();
实现类
@Service
public class UserServiceImpl implements UserService
@Override
public void saveUser()
System.out.println("save");
@Override
public String updateUser()
System.out.println("update");
return "abc";
4.4.3配置类
@ComponentScan(basePackages="com.czxy")
@EnableAspectJAutoProxy
public class SpringConfigruation
4.4.4切面类
@Component
@Aspect
public class MyAspect2
@Pointcut("execution(* com.czxy.service..*.*(..))☀️~算法系列之爆肝万字总结七种查找算法,持续补充更新中,建议收藏~☀️(代码片段)
🍅作者主页:Roninaxious🍅欢迎点赞👍收藏⭐留言📝🍅话不多说🍁开卷!🚢顺序查找算法🚢二分查找算法💥优化二分查找算法🚢插值查找算法🚢斐波那契查找算法🚢顺序... 查看详情
❤️爆肝万字整理的综合架构web服务之nginx详解❤️,附建议收藏(代码片段)
文章目录nginx服务配置详细介绍关于作者前言一、nginxweb入门简介1.1什么是nginx1.2常见的网站服务1.3nginx网站服务特点1.4网站页面访问原理二、nginx服务部署安装2.1实验环境2.2YUM安装2.3源码编译安装2.4nginx重要文件目录结构2.5虚拟主... 查看详情
熬夜爆肝万字c#基础入门大总结建议收藏(代码片段)
往期文章分享点击跳转=>熬夜再战Android从青铜到王者-UI组件快速搭建App界面点击跳转=>熬夜再战Android从青铜到王者-几个适配方案点击跳转=>熬夜再战Android从青铜到王者-开发效率插件篇点击跳转=>Unity粒子特... 查看详情
☀️~爆肝万字总结递归~❤️玩转算法系列之我如何才能掌握递归解题的能力❤️~十大经典问题助你突破极限~☀️(代码片段)
🍅作者主页:Roninaxious🍅欢迎点赞👍收藏⭐留言📝🚢前言🎐何为递归递归顾名思义就是´递´和´归´👀所谓的‘递’也就是“向下递去”,这个问题可以分解为若干个且形式相同的子问题... 查看详情
❤️爆肝六万字最全总结java数据库编程mybatis(建议收藏)(代码片段)
前言今天复习Java数据库编程,二话不说MyBatis手把手保姆级教程献上,再也不用担心学不会!资料:链接:https://pan.baidu.com/s/1FIDi_9QiTuhb4x7pksGOUQ提取码:kevf1.MyBatis入门文章目录前言1.MyBatis入门1.1概述1.2下载1.3与JDBC对比1.4入门案... 查看详情
❤️爆肝六万字最全总结java数据库编程mybatis(建议收藏)(代码片段)
前言今天复习Java数据库编程,二话不说MyBatis手把手保姆级教程献上,再也不用担心学不会!资料:链接:https://pan.baidu.com/s/1FIDi_9QiTuhb4x7pksGOUQ提取码:kevf1.MyBatis入门文章目录前言1.MyBatis入门1.1概述1.2下载1.3与JDBC对比1.4入门案... 查看详情
❤️大学三年沉淀,把我的学习经验分享给你,爆肝万字带你走进编程世界!❤️(代码片段)
Hello,大家好,我是Alex。时光匆匆,暑假过的很快,转眼又到了大学的开学季,我也是又混进了我们学院的新生群,发现大家对计算机充满着迷之向往,啊哈哈哈,不过没有人带着入门还是很容易... 查看详情
pythonopencv实战画图——这次一定能行!爆肝万字,建议点赞收藏~❤️❤️❤️(代码片段)
📢📢📢📣📣📣🌻🌻🌻Hello,大家好我叫是Dream呀,一个有趣的Python博主,小白一枚,多多关照😜😜😜🏅🏅 查看详情
熬夜爆肝万字c#基础入门大总结建议收藏(代码片段)
往期文章分享点击跳转=>熬夜再战Android从青铜到王者-UI组件快速搭建App界面点击跳转=>熬夜再战Android从青铜到王者-几个适配方案点击跳转=>熬夜再战Android从青铜到王者-开发效率插件篇点击跳转=>Unity粒子特... 查看详情
❤️❤️新生代农民工爆肝8万字,整理python编程从入门到实践(建议收藏)已码:8万字❤️❤️(代码片段)
人生苦短,我用Python开发环境搭建安装Python验证是否安装成功安装Pycharm配置pycharm编码规范基本语法规则保留字单行注释多行注释行与缩进多行语句数据类型空行等待用户输入print输出运算符算术运算符逻辑运算符成员运算符... 查看详情
(大厂必备)厂长熬夜爆肝万字之多线程高并发juc编程⭐学妹已收藏(代码片段)
🔥(大厂必备)厂长熬夜爆肝万字之多线程高并发JUC编程(一)⭐学妹已收藏❤️大家好,我是java厂长,今天带你们体验一把多线程高并发的面试高频!❤️关于作者作者介绍🍓博客主页:作者主页🍓... 查看详情
(大厂必备)厂长熬夜爆肝万字之多线程高并发juc编程⭐学妹已收藏(代码片段)
🔥(大厂必备)厂长熬夜爆肝万字之多线程高并发JUC编程(二)⭐学妹已收藏❤️大家好,我是java厂长,今天再次带你们体验一把多线程高并发的面试高频!❤️关于作者作者介绍🍓博客主页:作者主页... 查看详情
❤️❤️爆肝3万字整理小白入门与提升分布式版本管理软件:git,图文并茂(建议收藏)--已码一万字❤️❤️(代码片段)
小白快速快入门Git什么是GitSVNVSGit什么是版本控制安装Git谁在操作?Git本地仓库本地仓库构造重点Git常用基本操作gitaddgitcommitgitdiffgitloggitresetgitmvcheckoutgittagclearGithub使用教程什么是Github安装Github添加远程仓库找到key打开Github... 查看详情
❤️爆肝四万字的mysql总结全面整理+详细解释❤️(代码片段)
文章目录1.初识MySQL1.2数据库分类1.3MySQL简介1.4MySQL安装1.5MySQL(压缩包)安装配置1.6SQLyog使用的注意事项1.7连接数据库和一些基本命令2.操作数据库2.1操作数据库2.2数据库的数据类型(列类型)2.3数据库的字段属性2.4创建数据库表(... 查看详情
❤️六万字《spring框架从入门到精通》(建议收藏)❤️(代码片段)
❤️Spring代码:https://github.com/Donkequan/Spring-Study❤️希望各位博友三连+关注!!!1、简介spring理念:是现有的技术更加容易使用,本身是一个大杂烩。SSH:Struct2+Spring+HibernateSSM:Spri 查看详情
爆肝一周面试10多家中大厂后的万字总结——❤️javaweb篇❤️(建议收藏)(代码片段)
⭐欢迎订阅《大厂面试突击》专栏,面试10多家大厂总结出的高频面试知识,免费阶段大家赶快订阅⭐更多精品专栏简介点这里⭐更多大厂全路线学习视频+笔记,PC端看左侧「关于作者」,手机端「私信」博主... 查看详情
中秋节爆肝万字,带你熟悉linux进程的基本操作!!!(代码片段)
今天是中秋节,祝各位小伙伴中秋节快乐,记得吃月饼吖图片来自网络,侵联删Linux进程基本操作1.进程基本概念在Linux中进程信息被保存在task_struct(PCB)2.查看进程的方法pspsaux|greapmyprocls/proc3.创建进程fork():创建一个子进程#i... 查看详情
中秋节爆肝万字,带你熟悉linux进程的基本操作!!!(代码片段)
今天是中秋节,祝各位小伙伴中秋节快乐,记得吃月饼吖图片来自网络,侵联删Linux进程基本操作1.进程基本概念在Linux中进程信息被保存在task_struct(PCB)2.查看进程的方法pspsaux|greapmyprocls/proc3.创建进程fork():创建一个子进程#i... 查看详情