如果对于Spring的一些基础理论感兴趣可见👇
SSM【Spring SpringMVC Mybatis】—— Spring(一)
目录
1、Spring中bean的作用域
1.1 语法
1.2 四个作用域
2、Spring中bean的生命周期
2.1 bean的生命周期
2.2 bean的后置处理器
2.3 添加后置处理器后bean的生命周期
3、Spring中自动装配【基于XML】
3.1 Spring中提供两种装配方式
3.2 Spring自动装配语法及规则
3.3 总结
4、Spring中注解【非常重要】
4.1 使用注解将对象装配到IOC容器中
4.2 使用注解装配对象中属性【自动装配】
自动装配(Autowired):
限定装配(Qualifier):
字面量数值装配(Value):
5、Spring完全注解开发【0配置】
5.1 完全注解开发步骤
5.2 示例代码
6、AOP前奏
6.1 代理模式
6.2 为什么需要代理【程序中】
6.3 手动实现动态代理环境搭建
6.4 手动实现动态代理关键步骤
1、Spring中bean的作用域
1.1 语法
在bean标签中添加属性:scope属性即可
<bean id="myBean" class="com.example.MyBean" scope="singleton"/>
1.2 四个作用域
-
singleton(默认值):单例模式,容器中只存在一个bean实例。
- 对象创建时机:当创建Spring容器时,bean实例会被创建并放入容器中。
-
prototype:原型模式,每次获取bean时都会创建一个新的实例。
- 对象创建时机:当调用
getBean()
方法获取bean实例时,每次都会创建一个新的实例。
- 对象创建时机:当调用
-
request:请求作用域,每个HTTP请求都会创建一个新的bean实例。
- 对象创建时机:每次HTTP请求到达时,都会创建一个新的bean实例,并在当前请求结束后销毁。
- 当前请求:即URL不变的情况下,同一个HTTP请求中的所有处理都处于同一个请求域中。
-
session:会话作用域,每个HTTP会话都会创建一个新的bean实例。
- 对象创建时机:在用户会话开始时创建一个bean实例,并在用户会话结束后销毁。
- 当前会话:即用户在浏览器上不关闭、不更换的情况下持续访问应用的时间段。
2、Spring中bean的生命周期
2.1 bean的生命周期
-
通过构造器或工厂方法创建bean实例:Spring容器根据配置信息和依赖关系,使用构造器或工厂方法创建bean实例。
-
为bean的属性设置值和对其他bean的引用:Spring容器注入bean的属性值和依赖的其他bean。
-
调用bean的初始化方法:如果bean配置了初始化方法,Spring容器会在属性注入完成后调用该方法进行初始化。
-
bean可以使用了:bean初始化完成后,可以被其他bean或应用程序代码引用和使用。
-
当容器关闭时,调用bean的销毁方法:如果bean配置了销毁方法,当Spring容器关闭时,会调用该方法进行清理工作。
2.2 bean的后置处理器
作用:在调用初始化方法前后对bean进行额外的处理。
实现:
实现BeanPostProcessor接口
重写方法
postProcessBeforeInitialization(Object, String):在bean的初始化方法调用之前调用,允许修改bean的属性值或做其他处理。
postProcessAfterInitialization(Object, String):在bean的初始化方法调用之后调用,允许在bean初始化完成后进行额外的处理。
注意:装配后置处理器会为当前容器中每个bean均装配,不能为局部bean装配后置处理器
2.3 添加后置处理器后bean的生命周期
① 通过构造器或工厂方法创建bean实例
② 为bean的属性设置值和对其他bean的引用
postProcessBeforeInitialization(Object, String):在bean的初始化之前执行
③ 调用bean的初始化方法
postProcessAfterInitialization(Object, String):在bean的初始化之后执行
④ bean可以使用了
⑤ 当容器关闭时,调用bean的销毁方法
3、Spring中自动装配【基于XML】
3.1 Spring中提供两种装配方式
手动装配:通过XML文件或Java配置显式地指定bean之间的依赖关系。
自动装配:让Spring容器根据一定的规则自动将合适的bean注入到目标bean中,而不需要显式地在配置文件中声明这些依赖关系。
3.2 Spring自动装配语法及规则
在bean标签中添加属性:Autowire即可,
常用的有两种:
-
byName:根据属性名称自动装配。Spring会查找与属性名相同的bean,并将其注入到目标bean的属性中。
-
byType:根据属性类型自动装配。Spring会查找与属性类型相同的bean,并将其注入到目标bean的属性中。如果找到多个匹配的bean,则会报错。
注意:基于XML方式的自动装配只能装配非字面量数值(即不是直接指定的常量值)。
3.3 总结
在基于XML的自动装配中,底层实际上是通过setter方法进行注入的。但通常不推荐使用byName和byType方式进行自动装配,因为它们可能会导致不可预期的结果,特别是在大型项目中容易出现问题。相反,建议使用注解方式进行自动装配。
4、Spring中注解【非常重要】
4.1 使用注解将对象装配到IOC容器中
约定:约束>配置【注解>XML】>代码
位置:在类上面标识
注意:
Spring本身不区分四个注解【四个注解本质是一样的@Component】,提供四个注解的目的只有一个:提高代码的可读性
在使用注解装配对象时,Spring会默认将类名的首字母小写作为bean的ID。你也可以使用value
属性来指定bean的ID。
装配对象四个注解
@Component:装配普通组件到IOC容器
@Repository:装配持久化层组件到IOC容器
@Service:装配业务逻辑层组件到IOC容器
@Controller:装配控制层|表示层组件到IOC容器
使用注解步骤
导入相关jar包【已导入】
开启组件扫描
<!-- 开启组件扫描
base-package:设置扫描注解包名【当前包及其子包】
-->
<context:component-scan base-package="com.atguigu"></context:component-scan>
使用注解标识组件
4.2 使用注解装配对象中属性【自动装配】
自动装配(Autowired):
- 使用@Autowired注解可以实现对象属性的自动装配。
- 装配原理基于反射机制,Spring会尝试按照byType进行匹配。
- 如果匹配到一个对象,则正常使用。
- 如果匹配不到对象,默认情况下会报错,但可以通过设置@Autowired(required=false)来避免报错。
- 如果匹配到多个对象,会尝试按照byName进行唯一筛选,如果筛选失败则报错。
- @Autowired注解的required属性可以设置为true或false,表示是否必须装配对象。
/*expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
*/
限定装配(Qualifier):
@Qualifier注解
作用:配合@Autowired一起使用,将设置beanId名称装配到属性中
注意:不能单独使用,需要与@Autowired一起使用
字面量数值装配(Value):
@Value注解
作用:装配对象中属性【字面量数值】
5、Spring完全注解开发【0配置】
5.1 完全注解开发步骤
5.1.1. 创建配置类
5.1.2. 在class上面添加注解
@Configuration:标识当前类是一个配置类,作用:代替XML配置文件
@ComponentScan:设置组件扫描当前包及其子包
5.1.3. 使用AnnotationConfigApplicationContext容器对象
5.2 示例代码
@Configuration
@ComponentScan(basePackages = "com.atguigu")
public class SpringConfig {
}
@Test
public void test0Xml(){
//创建容器对象
// ApplicationContext context =
// new ClassPathXmlApplicationContext("applicationContext.xml");
//使用AnnotationConfigApplicationContext容器对象
ApplicationContext context =
new AnnotationConfigApplicationContext(SpringConfig.class);
DeptDaoImpl deptDao = context.getBean("deptDao", DeptDaoImpl.class);
System.out.println("deptDao = " + deptDao);
}
6、AOP前奏
6.1 代理模式
代理模式:我们需要做一件事情,又不期望自己亲力亲为,此时,可以找一个代理【中介】
我们【目标对象】与中介【代理对象】不能相互转换,因为是“兄弟”关系
6.2 为什么需要代理【程序中】
需求:实现【加减乘除】计算器类
在加减乘除方法中,添加日志功能【在计算之前,记录日志。在计算之后,显示结果。】
实现后发现问题如下
日志代码比较分散,可以提取日志类
日志代码比较混乱,日志代码【非核心业务代码】与加减乘除方法【核心业务代码】书写一处
总结:在核心业务代码中,需要添加日志功能,但不期望在核心业务代码中书写日志代码。
此时:使用代理模式解决问题【先将日志代码横向提取到日志类中,再动态织入回到业务代码中】
6.3 手动实现动态代理环境搭建
实现方式
基于接口实现动态代理: JDK动态代理
基于继承实现动态代理: Cglib、Javassist动态代理
实现动态代理关键步骤
一个类:Proxy
概述:Proxy代理类的基类【类似Object】
作用:newProxyInstance():创建代理对象
一个接口:InvocationHandler
概述:实现【动态织入效果】关键接口
作用:invoke(),执行invoke()实现动态织入效果
6.4 手动实现动态代理关键步骤
注意:代理对象与实现类【目标对象】是“兄弟”关系,不能相互转换
创建类【为了实现创建代理对象工具类】
提供属性【目标对象:实现类】
提供方法【创建代理对象】
提供有参构造器【避免目标对为空】
package com.atguigu.beforeaop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyProxy {
/**
* 目标对象【目标客户】
*/
private Object target;
public MyProxy(Object target){
this.target = target;
}
/**
* 获取目标对象的,代理对象
* @return
*/
public Object getProxyObject(){
Object proxyObj = null;
/**
类加载器【ClassLoader loader】,目标对象类加载器
目标对象实现接口:Class<?>[] interfaces,目标对象实现所有接口
InvocationHandler h
*/
ClassLoader classLoader = target.getClass().getClassLoader();
Class<?>[] interfaces = target.getClass().getInterfaces();
//创建代理对象
proxyObj = Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
//执行invoke()实现动态织入效果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取方法名【目标对象】
String methodName = method.getName();
//执行目标方法之前,添加日志
MyLogging.beforeMethod(methodName,args);
//触发目标对象目标方法
Object rs = method.invoke(target, args);
//执行目标方法之后,添加日志
MyLogging.afterMethod(methodName,rs);
return rs;
}
});
return proxyObj;
}
// class invocationImpl implements InvocationHandler{
// }
}
@Test
public void testBeforeAop(){
// int add = calc.add(1, 2);
// System.out.println("add = " + add);
//目标对象
Calc calc = new CalcImpl();
//代理工具类
MyProxy myProxy = new MyProxy(calc);
//获取代理对象
Calc calcProxy = (Calc)myProxy.getProxyObject();
//测试
// int add = calcProxy.add(1, 2);
int div = calcProxy.div(2, 1);
}