目录
3.将第三方类交给的IOC容器管理的三种方式(使用纯注解开发)
九 :Spring xml配置AOP: 了解一下即可,知道可以配置就可以
引入:
一: 学习Spring框架的原因
1.简化开发
2.可以整合其他技术(框架)
二: Spring的核心概念
1. IOC(Inversion of Control) 控制反转, 即将new对象的权利由程序转到外部(Spring的 IOC容器
2. DI(Dependency injection) 依赖注入, 即在IOC容器中建立Bean与Bean之间的依赖关系
Spring 1 IOC&DI&Bean
一:IOC
1.IOC的定义
IOC就是控制反转, 即将new对象的权利由程序转到外部(Spring的 IOC容器)
Note:Spring提供了一个容器,称为IOC容器, IOC容器负责对象的创建、初始化等一 系列工作,被创建或被管理的对象在IOC容器中统称为Bean
2.将自己编写的类交给的IOC容器管理的两种方式
方式一: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标签:表示配置bean id属性:表示给bean起名字 class属性:表示给bean定义类型-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
</beans>
方式二:SpringBoot中使用注解 (@Component,@Controller,@RestController,@Service@Repository等注解)
eg1:(注解后不起名字,在获取该Bean时为该类类名的首字母小写,即dao)
@Component
@RestController
@Controller
@Service
@Repository
//以上注解都可将当前的对象加载进IOC容器中,不局限这几个注解,还有其他的注解
class Dao{
}
eg2:(注解后起名字,在获取该Bean时为自己起的名字,即bookdao)
/*
@Component("bookDao")
@Controller("bookDao")
@RestController("bookDao")
@Service("bookDao")
*/
@Repository("bookDao") //如果注解后面不起名字的默认就是类名首字母小写即bookDaoImpl
public class BookDaoImpl implements BookDao{
@Override
public Object select() {
return "ccc";
}
}
3.将第三方类交给的IOC容器管理的三种方式(使用纯注解开发)
纯注解开发需要使用注解进行配置,我们无法修改三方包中的类,不能进去给人家写好 的类加@Compent等注解,可以采用如下方式
方式一:使用@Configuration注解设置配置类,然后使用@Bean注解以及@Autowired注解
@Configuration //配置当前类为配置类
public class getDatasource{
@Bean //bean的名字默认是方法名,但是可以起名字@Bean("datasource")
public Demo1 demo1(@Autowired Datasource ds){
return new Demo1(ds);
}
}
class Demo1 {
}
方式二:使用@Import注解:
public class JdbcConfig {
//@Bean:表示当前方法的返回值是一个bean对象,添加到IOC容器中
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}
@Configuration
@ComponentScan("com.itheima")
//@Import:导入配置信息
@Import({JdbcConfig.class})
public class SpringConfig {
}
方式三:使用@ConponentScan,这个只能识别Spring注解标识的类
4.从IOC容器中获取Bean的两种方式
方式一:Spring中使用xml配置文件
public class App {
public static void main(String[] args) {
//1.创建IoC容器对象,加载spring核心配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2 从IOC容器中获取Bean对象(BookService对象)--根据Bean名称获取(缺点:需要自己强制类型转换)
BookService bookService= (BookService)ctx.getBean("bookService");
//从IOC容器中获取Bean对象(BookService对象)--根据Bean名称获取并指定类型(推荐)
//BookDao bookDao = ctx.getBean("bookDao", BookDao.class);
//从IOC容器中获取Bean对象(BookService对象)--根据Bean类型获取(缺点:如果IOC容器中同类型的Bean对象有多个,此处获取会报错)
//BookDao bookDao = ctx.getBean(BookDao.class);
//3 调用Bean对象(BookService对象)的方法
bookService.save();
}
}
方式二:SpringBoot中使用注解
public static void main(String[] args) {
ConfigurableApplicationContext run =
SpringApplication.run(AbcApplication.class, args);
//eg 1
//实现可能是多个
//BookService bookServiceImpl = run.getBean("bookServiceImpl",BookService.class);
//eg 2
//BookDaoImpl bookDao = run.getBean("bookDao", BookDaoImpl.class);
//eg 3
BookService bookServiceImpl = (BookService) run.getBean("bookServiceImpl");
bookServiceImpl.said();
}
二:DI
1.DI的定义
DI(Dependency Injection)即在IOC容器中建立Bean与Bean之间的依赖关系
2.演示DI的两种方式
方式一: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">
<!--setter方法注入简单类型-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<property name="connectionNumber" value="10"/>
</bean>
<!--setter方法注入引用类型-->
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
</bean>
</beans>
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<constructor-arg name="connectionNumber" value="10"/>
</bean>
<!--构造方法注入引用类型-->
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
</beans>
方式二:SpringBoot中使用注解
(注入引用类型使用@Autowired,@Qualifier,@Resource注解
注入简单类型使用@Value等注解)
Note:
1.@Autowired:按照bean类型进行自动装配的,还可以用于方法参数
2.@Autowired:搭配@Qualifier:按照bean名称进行装配,相当于@Resource注解 3.@Resource:按照bean名称进行装配 4.@Value:注入加载进IOC容器中的配置文件里的属性的值
Eg:注解开发注入引用类型
@Service
public class BookServiceImpl implements BookService {
@Autowired //@Autowired:注入引用类型,自动装配模式,默认按类型装配
private BookDao bookDao; //如果实现类中不配注解则表示随机给个BookDao接口的实现类;如果实现类中使用@Order,@Primary则可以改实现类的优先级来决定装配哪个实现类
//@Autowired
//private BookDaoImpl2 bookDao; //直接指定具体的BookDao接口的实现类
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
@Service
public class BookServiceImpl implements BookService {
//@Autowired:注入引用类型,自动装配模式,默认按类型装配
//@Qualifier:自动装配bean时按bean名称装配, @Qualifier注解无法单独使用,必须配合@Autowired注解使用
@Autowired
@Qualifier("bookDao")
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
@Component
public class BookServiceImpl implements BookService{
@Resource(name="bookDaoImpl2") //@Resource:按照bean名称进行装配
private BookDao bookDao;
@Override
public void said() {
Object select = bookDao.select();
System.out.println(select);
}
}
Eg:注解开发注入简单类型
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
@Value("${name}") //@Value:注入简单类型(无需提供set方法)
private String name;
public void save() {
System.out.println("book dao save ..." + name);
}
}
@Configuration
@ComponentScan("com.itheima")
//@PropertySource加载properties配置文件
@PropertySource({"classpath:jdbc.properties"}) //{}可以省略不写
public class SpringConfig {
}
三:Bean
1.Bean的定义
--Bean就是你理解的new class后的对象,使用了@Component以及@Component衍生的注解后,IOC会自己new 一个对应的class对象加载进容器
--使用xml文件在里面进行的配置都是在对bean做数据的封装,就是给bean各个属性赋值 例如: 学生类,在xml文件中会设置id=....,name=....,都是在标签中,其实就是使用底层其实就是学生类的get/set方法
--总结: Spring的IOC容器的每一个类都是一个bean
-- 深入理解: 每一个Bean在创建的时候都可以进行一些特定操作,AOP 就是利用这个特性
2.Bean的生命周期配置
方式一:Spring中使用xml配置文件配置Bean的生命周期
<!--init-method:设置bean初始化生命周期回调函数,此处填写init方法名-->
<!--destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象,此处填写destory方法名-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
//表示bean初始化对应的操作
public void init(){
System.out.println("init...");
}
//表示bean销毁前对应的操作
public void destory(){
System.out.println("destory...");
}
}
方式二:SpringBoot中使用注解配置Bean的生命周期
(@PostConstruct,@PreDestroy注解)
@PostConstruct //表示bean初始化对应的操作
public void init(){
System.out.println("init...");
}
@PreDestroy //表示bean销毁前对应的操作
public void destory(){
System.out.println("destory...");
}
Note:1.@PostConstruct和 @PreDestroy是JavaEE的注解,不是Spring的
2.从JDK9开始,jdk中的javax.annotation包被移除了,也就是说这两个注解就用不了 了,可以额外导入下面依赖解决这个问题
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
更多的生命周期相关的,参考下面,不需要细看,暂时知道有这样一回事就行,后面得会
Spring中初始化时执行相关操作_spring初始化完成后执行一些操作_楠~枫的博客-CSDN博客
3.Bean的作用范围配置
简单的理解,就像是一人一把工具还是多个人都使用一把工具,这个作用范围就是来限制这个的
方式一:Spring中使用xml配置文件配置Bean的作用范围
scope的取值不仅仅只有singleton和prototype,还有request、session、application、 websocket 表示创建出的对象放置在web容器(tomcat)对应的位置。比如:request表示保存到request域中
方式二:SpringBoot中使用注解配置Bean的作用范围
( @Scope(value="singleton"), @Scope(value="prototype")注解 )
@Component
@Scope(value = "singleton")
//@Scope(value = "prototype")
public class BeanLimitScope {
}
Spring 2 Spring容器&Spring注解开发
一:Spring容器
1.Spring创建容器的两种方式
2.Spring容器类的层次结构
- BeanFactory是IOC容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载
- ApplicationContext接口是Spring容器的核心接口,初始化时bean立即加载
- ApplicationContext接口提供基础的bean操作相关方法,通过其他接口扩展其功能
- ApplicationContext接口常用初始化类有ClassPathXmlApplicationContext以及FileSystemXmlApplicationContext
二:Spring注解开发
1.使用Spring注解开发的目的
xml配置Bean对象有些繁琐,使用注解简化Bean对象的定义
2.使用Spring注解开发的步骤
步骤一:在applicationContext.xml中开启Spring注解包扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--扫描com.itheima包及其子包下的类中注解-->
<context:component-scan base-package="com.itheima"/>
</beans>
步骤二:在类上使用@Component注解定义Bean
@Component("bookDao") //@Component定义bean
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
@Component
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}`
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
步骤三:在测试类上获取Bean对象
public class AppForAnnotation {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
System.out.println(bookDao);
//按类型获取bean
BookService bookService = ctx.getBean(BookService.class);
System.out.println(bookService);
}
}
3.Spring的常用注解
Spring提供@Component注解的三个衍生注解
@Controller:用于表现层bean定义
@Service:用于业务层bean定义
@Repository:用于数据层bean定义
三:Spring纯注解开发
1.纯注解开发模式介绍
Spring3.0开启了纯注解开发模式,使用Java类替代配置文件,开启了Spring快速开发赛道
@Configuration注解用于设定当前类为配置类
@ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式
@ComponentScan({com.itheima.service","com.itheima.dao"})
加载Spring核心配置文件初始化容器对象变为加载Java配置类初始化容器对象
//加载配置类初始化容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
2.Spring纯注解开发的代码演示:
步骤一:定义配置类
//声明当前类为Spring配置类
@Configuration
//Spring注解扫描,相当于<context:component-scan base-package="com.itheima"/>
@ComponentScan("com.itheima")
//设置bean扫描路径,多个路径书写为字符串数组格式
//@ComponentScan({"com.itheima.service","com.itheima.dao"})
public class SpringConfig {
}
步骤二:在测试类中加载配置类,获取Bean对象并使用
public class AppForAnnotation {
public static void main(String[] args) {
//AnnotationConfigApplicationContext加载Spring配置类初始化Spring容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
System.out.println(bookDao);
//按类型获取bean
BookService bookService = ctx.getBean(BookService.class);
System.out.println(bookService);
}
3.Spring纯注解开发的常用注解:
1. @Configuration注解用于设定当前类为配置类,就是替换xml的用的
@Configuration//本类首先是配置类
public class BeanIoc {
@Bean//bean的名字默认是方法名,但是可以起名字@Bean("aaaa")
public Demo1 demo1() {
return new Demo1();
}
}
2 @ComponentScan注解,扫描使用Spring注解标识的类,如@Component和他的衍生注解标识的类
//声明当前类为Spring配置类
@Configuration
//Spring注解扫描,相当于<context:component-scan base-package="com.itheima"/>
@ComponentScan("com.itheima")
//设置bean扫描路径,多个路径书写为字符串数组格式
//@ComponentScan({"com.itheima.service","com.itheima.dao"})
public class SpringConfig {
}
3 @Value注解: 其实就是读取配置类或配置文件中的属性,将配置文件中的属性赋值给当前的变量,前提是在IOC中得有这@Value("name"")中的name的值
(1)@Value注解可以读取Spring xml 中的xml的值
<bean class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="1111"/>
<property name="url" value="1111"/>
<property name="username" value="11111"/>
<property name="password" value="111"/>
</bean>
(2)@Value注解可以读取SpringBoot的application.yml/properties中的值
spring: datasource: #数据源 driver-class-name: com.mysql.cj.jdbc.Driver #数据库驱动 url: jdbc:mysql://localhost:3306/test # 数据库的 JDBC URL username: root #数据库的登录用户名 password: root #数据库的登录密码
//@Configuration 只要这个bean加载进ioc,就会自动去获取值
@Component
public class TestValue {
public class JdbcConfig {
@Value("spring.datasource.username")
private String userName;
}
}
4 @PropertySource注解: 可以读取自定义的Properties文件加载进IOC容器后的值
@Configuration
//@PropertySource加载properties配置文件,将jdbc.properties文件中的属性加载进ioc环境中
@PropertySource({"classpath:jdbc.properties"}) //{}可以省略不写
public class SpringConfig {
}
下面的链接,这里面的注解,必须,必须知道是干啥用
Spring 3 AOP
一:AOP的简介以及作用
简介: AOP(Aspect Oriented Programming) 面向切面编程,一种编程范式,区别于 OOP
(ObjectOriented Programming)面向对象编程
作用:就是不改变原来的代码逻辑,在原来的逻辑执行前,执行中,或者执行后可以做一些操作
二: 原理:
其实就是java的动态代理和反射,(Spring使用的是cglib动态代理的本质上也是java的动态代理,只是做了层包装)
三: AOP中的重要概念
-
代理(Proxy):SpringAOP的核心本质是采用代理模式实现的
-
连接点(JoinPoint): 在SpringAOP中,理解为任意方法的执行
-
切入点(Pointcut):进行功能增强了的方法
-
通知(Advice):若干个方法的共性功能,最终体现为一个方法, 在切入点前后执行的操作
-
切面(Aspect):描述通知与切入点的对应关系
-
目标对象(Target):被代理的原始对象成为目标对象
四: 切入点表达式语法
-
切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数)异常名)
-
execution(* com.itheima.service.Service.(..))
-
-
切入点表达式描述通配符:
-
作用:用于快速描述,范围描述
-
* :匹配任意符号(常用)
-
.. :匹配多个连续的任意符号(常用)
-
+ :匹配子类类型
-
-
切入点表达式书写技巧
1.按标准规范开发 2.查询操作的返回值建议使用*匹配 3.减少使用..的形式描述包 4.对接口进行描述,使用*表示模块名,例如UserService的匹配描述为*Service 5.方法名书写保留动词,例如get,使用*表示名词,例如getById匹配描述为getBy* 6.参数根据实际情况灵活调整
五: 五种通知类型
-
前置通知(@Before)
-
后置通知(@After)
-
环绕通知(@Around)
-
返回后通知(@AfterReturning)
-
抛出异常后通知(@AfterThrowing)
-------------------------------------------------------------------------------------------------
环绕通知依赖形参ProceedingJoinPoint才能实现对原始方法的调用
环绕通知可以隔离原始方法的调用执行
环绕通知返回值设置为Object类型
环绕通知中可以对原始方法调用过程中出现的异常进行处理
-------------------------------------------------------------------------------------------------
六:Spring中使用AOP的注意事项:
就是你需要做操作的类必须是加载进IOC的,就是使用IOC进行管理的,同时你在获取这个类的对象时候也必须通过IOC获取,简单的将就是不能new,只有通过IOC去操作,才可以在类创建对象的时候进行一些操作,前面的Bean时候已经和你说了,bean的初始化,以及生命周期等,利用的就是这个
七: AOP的使用场景举例:
Spring中的好多智能化操作都是AOP,拦截器就是AOP
接口鉴权角色认证,实现某个接口只能拥有某种角色才可以访问等,
某个业务模块只做业务,日志服务可以在业务服务后通过AOP记录操作日志等应用场景
八: 学习目标:
学完忘了咋操作,咋写代码都可以,但是得知道这个可以做啥,用到去百度,重要的是思想,是思想,这块重要的是思想,操作得有,但是思想才是主要的,面试基本都会问
九 :Spring xml配置AOP: 了解一下即可,知道可以配置就可以
十:纯注解开发(使用SpringBoot):
引入依赖:
<!-- aop切面 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
@Controller
public class AOPControllerTest {
/***
* aop 案例
*/
@GetMapping("aop")
public Object aopTest(String name){
System.out.println("接口收到参数,"+name);
return name;
}
}
package com.example.abc.sp3;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
//通知类必须配置成Spring管理的bean
@Component
//设置当前类为切面类类
@Aspect
public class MyAdvice {
//设置切入点,@Pointcut注解要求配置在方法上方
@Pointcut("execution(* com.example.abc.sp3.AOPControllerTest.aopTest(..))")
private void pt(){}
/**
- 名称:**@Before**
- 类型:方法注解
- 位置:通知方法定义上方
- 作用:设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法前运行
*/
@Before("pt()")
public void method(){
System.out.println("Before advice");
}
/**
- 名称:**@After**
- 类型:方法注解
- 位置:通知方法定义上方
- 作用:设置当前通知方法与切入点之间的绑定关系,当**前通知方法在原始切入点方法后运行**
*/
@After("pt()")
public void after() {
System.out.println("after advice ...");
}
/**
- @AfterReturning**(了解)
- 类型:方法注解
- 位置:通知方法定义上方
- 作用:设置当前通知方法与切入点之间的绑定关系,当**前通知方法在原始切入点方法正常执行完毕后才能运行**
*/
// @AfterReturning("pt()")
public void afterReturning() {
System.out.println("afterReturning advice ...");
}
/**
* - 名称:**@Around**(重点,常用)
* - 类型:方法注解
* - 位置:通知方法定义上方
* - 作用:设置当前通知方法与切入点之间的绑定关系,当**前通知方法在原始切入点方法前后运行**
*/
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around before advice ...");
//获取原来方法的参数
Object[] args = pjp.getArgs();
System.out.println(Arrays.toString(args)+": "+"around");
//调原来的方法
Object ret = pjp.proceed(args);
System.out.println("around after advice ...");
//使用AOP做增强以后,如果原始切入点方法有返回值,通知方法也需要有返回值
return ret;
}
/**
* - 名称:**@AfterThrowin**g(了解)
* - 类型:方法注解
* - 位置:通知方法定义上方
* - 作用:设置当前通知方法与切入点之间的绑定关系,**当前通知方法在原始切入点方法运行抛出异常后执行**
* - 范例:
*/
@AfterThrowing("pt()")
public void afterThrowing() {
System.out.println("afterThrowing advice ...");
}
}
环绕通知注意事项:
-
环绕通知方法形参必须是ProceedingJoinPoint,表示正在执行的连接点,使用该对象的proceed()方法表示对原始对象方法进行调用,返回值为原始对象方法的返回值
-
环绕通知方法的返回值建议写成Object类型,用于将原始对象方法的返回值进行返回,哪里使用代理对象就返回到哪里