赞
踩
Spring 是最受欢迎的企业级 Java 应用程序开发框架,数以百万的来自世界各地的开发人员使用 Spring 框架来创建性能好、易于测试、可重用的代码
Spring 框架是一个开源的 Java 平台,它最初是由 Rod Johnson 编写的,并且于 2003 年 6 月首次在 Apache 2.0 许可下发布
Spring 是轻量级的框架,其基础版本只有 2 MB 左右的大小
Spring 框架的核心特性是可以用于开发任何 Java 应用程序,但是在 Java EE 平台上构建 web 应用程序是需要扩展的。 Spring 框架的目标是使 J2EE 开发变得更容易使用,通过启用基于 POJO 编程模型来促进良好的编程实践
•**非侵入式:**基于Spring开发的应用中的对象可以不依赖于Spring的API
•**控制反转:**IOC——Inversion of Control,指的是将对象的创建权交给 Spring 去创建。使用 Spring 之前,对象的创建都是由我们自己在代码中new创建。而使用 Spring 之后。对象的创建都是给了 Spring 框架。
•**依赖注入:**DI——Dependency Injection,是指依赖的对象不需要手动调用 setXX 方法去设置,而是通过配置赋值。
•**面向切面编程:**Aspect Oriented Programming——AOP
•**容器:**Spring 是一个容器,因为它包含并且管理应用对象的生命周期
•**组件化:**Spring 实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。
•**一站式:**在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上 Spring 自身也提供了表现层的 SpringMVC 和持久层的 Spring JDBC)
依赖注入(DI):
Spring 最认同的技术是控制反转的依赖注入(DI)模式。控制反转(IoC)是一个通用的概念,它可以用许多不同的方式去表达,依赖注入仅仅是控制反转的一个具体的例子。
当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能的独立于其他的 Java 类来增加这些类可重用可能性,当进行单元测试时,可以使它们独立于其他类进行测试。依赖注入(或者有时被称为配线)有助于将这些类粘合在一起,并且在同一时间让它们保持独立。
面向切面的程序设计(AOP):
Spring 框架的一个关键组件是面向切面的程序设计(AOP)框架。一个程序中跨越多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样常见的很好的关于方面的例子,比如日志记录、声明性事务、安全性,和缓存等等。
在 OOP 中模块化的关键单元是类,而在 AOP 中模块化的关键单元是方面。AOP 帮助你将横切关注点从它们所影响的对象中分离出来,然而依赖注入帮助你将你的应用程序对象从彼此中分离出来。
•JDBC 模块:提供了 JDBC 抽象层,它消除了冗长的 JDBC 编码和对数据库供应商特定错误代码的解析。
•ORM 模块:提供了对流行的对象关系映射 API 的集成,包括 JPA、JDO 和 Hibernate 等。通过此模块可以让这些 ORM 框架和 spring的其它功能整合,比如前面提及的事务管理。
•OXM 模块:提供了对 OXM 实现的支持,比如 JAXB、Castor、XML Beans、JiBX、XStream 等。
•JMS 模块:包含生产(produce)和消费(consume)消息的功能。从 Spring 4.1 开始,集成了 spring-messaging 模块。
事务模块:为实现特殊接口类及所有的 POJO 支持编程式和声明式事务管理
•Web 模块:提供面向 web 的基本功能和面向 web 的应用上下文,比如多部分(multipart)文件上传功能、使用 Servlet 监听器初始化 IoC 容器等。它还包括 HTTP 客户端以及 Spring 远程调用中与 web 相关的部分。
•Web-MVC 模块:为 web 应用提供了模型视图控制(MVC)和 REST Web服务的实现。Spring 的 MVC 框架可以使领域模型代码和 web 表单完全地分离,且可以与 Spring 框架的其它所有功能进行集成。
•**Web-Socket 模块:**为 WebSocket-based 提供了支持,而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式。
•**Web-Portlet 模块:**提供了用于 Portlet 环境的 MVC 实现,并反映了 spring-webmvc 模块的功能。
•AOP 模块:提供了面向方面(切面)的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,从而使实现功能的代码彻底的解耦出来。使用源码级的元数据,可以用类似于.Net属性的方式合并行为信息到代码中。
•Aspects 模块:提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。
•Instrumentation 模块:在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。
•**Messaging 模块:**为 STOMP 提供了支持作为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。
•**测试模块:**支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试。
<!-- spring核心包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.13</version>
</dependency>
<!-- junt单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
在resouce目录下创建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">
<!-- User类的对象就交给Spring管理了 -->
<bean id="user" class="com.huawei.SpringDemo2023.User" />
</beans>
在text/java 目录下创建测试类进行测试
//单元测试注解,代表可以直接运行该方法测试,需要依赖Junit类库
@Test
public void test1(){
/**
* 测试从Spring容器中取得指定的实例
* 1.加载Spring配置文件
* 2.取出Bean容器中的实例
* 3.调用类中的方法
*/
//1.加载Spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
//2.取出Bean容器中的实例
User user = (User)context.getBean("user");
//3.调用方法
user.say();
}
简介:
Spring 容器是 Spring 框架的核心。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。这些对象被称为 Spring Beans
技术功能:
IOC 容器具有依赖注入功能的容器,它可以创建对象,IOC 容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。通常new一个实例,控制权由程序员控制,而"控制反转"是指new实例工作不由程序员来做而是交给Spring容器来做。在Spring中BeanFactory是IOC容器的实际代表者。
注意:
ApplicationContext 容器包括 BeanFactory 容器的所有功能,所以通常不建议使用BeanFactory。BeanFactory 仍然可以用于轻量级的应用程序,如移动设备或基于 applet 的应用程序,其中它的数据量和速度是显著。
概述:
这是一个最简单的容器,它主要的功能是为依赖注入 (DI) 提供支持,这个容器接口在 org.springframework.beans.factory.BeanFactory中被定义。
在 Spring 中,有大量对 BeanFactory 接口的实现。其中,最常被使用的是 XmlBeanFactory 类。这个容器从一个 XML 文件中读取配置元数据,由这些元数据来生成一个被配置化的系统或者应用。
加载容器配置的方法案例:
/**
* BeanFactory创建实例步骤
* 1.创建工厂类,加载Bean.xml配置文件
* 2.通过工厂的方法获取指定对象实例
* 3.实例对象调用方法
*/
//1.创建工厂类,加载Bean.xml配置文件
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("Bean.xml"));
//2.通过工厂的方法获取指定对象实例
User user = (User) factory.getBean("user");
//3.实例对象调用方法
user.say();
概述:
Application Context 是 BeanFactory 的子接口,也被称为 Spring 上下文。
Application Context 是 spring 中较高级的容器。和 BeanFactory 类似,它可以加载配置文件中定义的 bean,将所有的 bean 集中在一起,当有请求的时候分配 bean。 另外,它增加了企业所需要的功能,ApplicationContext 包含 BeanFactory 所有的功能,一般情况下,相对于 BeanFactory,ApplicationContext 会更加优秀。
Applicationcontext容器提供了三种加载ioc容器的实现:
•ClassPathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你不需要提供 XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量即可,因为,容器会从 CLASSPATH 中搜索 bean 配置文件。
•FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你需要提供给构造器 XML 文件的完整路径。
•WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean。
//1. 加载配置文件,初始化容器
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
//2. 通过同期的getBean方法获取容器中创建的对象
User user = (User) context.getBean("user");
System.out.println("2. 从容器中获取对象");
user.say();
/**
*第一步生成工厂对象。加载完指定路径下 bean 配置文件后,利用框架提供的 FileSystemXmlApplicationContext *API 去生成工厂 bean
*/
ApplicationContext context = new FileSystemXmlApplicationContext
("C:/Users/ZARA/workspace/HelloSpring/src/Beans.xml");
//第二步利用第一步生成的上下文中的 getBean() 方法得到所需要的 bean。 这个方法通过配置文件中的 bean ID 来返回一个真正的对象。
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
//来调用任何方法
obj.getMessage();
当在 Spring 中定义一个 bean 时,你必须声明该 bean 的作用域的选项。
Spring 框架支持以下五个作用域,分别为 : singleton、prototype、request、session 和 global session
spring配置文件配置方法
<bean id="user" scope="prototype" class="com.huawei.SpringDemo2023.User" />
Bean的生命周期可以表达为:Bean的定义——Bean的初始化——Bean的使用——Bean的销毁
当配置上lazy-init=true之后,表示该bean是懒加载模式,什么时候用到了该bean才会进行初始化。
它有两个值:true,false(默认)true表示该bean是懒加载,容器初始化的时候不进行初始化。
<bean id="user" lazy-init="false" class="com.huawei.SpringDemo2023.User" />
spring.xml配置文件中,对应的bean标签是不需要配置init-method属性
bean类
public class User implements InitializingBean {
private String name;
public User(){
System.out.println("我被实例了!");
}
public void say(){
System.out.println("我被调用了!");
}
/**
* 初始化回调-在对象创建完成之后
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("init初始化-afterPropertiesSet()");
}
}
测试
//1. 加载配置文件,初始化容器
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
非侵入式的配置方法
spring配置文件中
<bean id="user" init-method="userInit" class="com.huawei.SpringDemo2023.User" />
在bean类中定义userInit方法
public class User{
private String name;
public User(){
System.out.println("我被实例了!");
}
public void say(){
System.out.println("我被调用了!");
}
/**
* 初始化回调-在对象创建完成之后
* @throws Exception
*/
public void userInit(){
System.out.println("userInit调用!");
}
}
public class User implements DisposableBean {
private String name;
public User(){
System.out.println("我被实例了!");
}
public void say(){
System.out.println("我被调用了!");
}
/**
* 当对象销毁时回到
* @throws Exception
*/
@Override
public void destroy() throws Exception {
System.out.println("destroy-调用");
}
}
<bean id="user" destroy-method="userDes" class="com.huawei.SpringDemo2023.User" />
bean类内
public class User{
private String name;
public User(){
System.out.println("我被实例了!");
}
public void say(){
System.out.println("我被调用了!");
}
/**
* 当对象销毁时回到
* @throws Exception
*/
public void userDes(){
System.out.println("userDes-调用");
}
}
测试
//1. 加载配置文件,初始化容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
// registerShutdownHook 方法是关闭所有bean,触发销毁
context.registerShutdownHook();
作用:
当容器中的bean调用的init-method方法回调时,在调用方法之前和之后添加操作
执行流程
创建一个前后置处理器类
package com.huawei.SpringDemo2023;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* 前后置处理器类
* 2023/2/9
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
* 前置处理器
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("-----------1.前置处理器--------------");
System.out.println("bean:"+bean);
System.out.println("beanName:"+bean);
return bean;
}
/**
* 后置处理器
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("-----------2.后置处理器--------------");
System.out.println("bean:"+bean);
System.out.println("beanName:"+bean);
return bean;
}
}
在spring中配置前后置处理器类的实例
<!-- User类的对象就交给Spring管理了 -->
<bean id="user" init-method="userInit" class="com.huawei.SpringDemo2023.User" />
<bean id="stu" init-method="initStu" class="com.huawei.SpringDemo2023.Student" />
<!-- 前后置处理器类 -->
<bean id="myBeanPostProcessor" class="com.huawei.SpringDemo2023.MyBeanPostProcessor" />
注意:前后置处理器的触发即使不定义init方法也会触发,时机变为调用构造器前后
1.重写getOrder方法后,返回值值越小,执行优先级越高
2.执行优先级相同,根据Spring配置的文件中,配置bean的先后顺序作为优先级
/**
* 前后置处理器类
* 2023/2/9
*/
public class MyBeanPostProcessor implements BeanPostProcessor, Ordered {
/**
* 前置处理器
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("-----------1.MyBeanPostProcessor-前置处理器--------------");
return bean;
}
/**
* 后置处理器
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("-----------2.MyBeanPostProcessor-后置处理器--------------");
return bean;
}
/**
* 执行先后的顺序 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* @return
*/
@Override
public int getOrder() {
return 800;// 值越小执行优先级越高
}
}
调用bean类的set方法进行属性的注入
<!-- User类的对象就交给Spring管理了 -->
<bean id="user" class="com.huawei.SpringDemo2023.User" >
<property name="name" value="cxk" />
</bean>
public class User{
private String name;
public User(){
System.out.println("我被实例了!");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("user-set方法调用-value:"+name);
this.name = name;
}
}
<!-- 定义一个抽象模板 -->
<bean id="templateA" abstract="true">
<property name="name" value="123"></property>
</bean>
<!-- bean类通过parent属性继承 -->
<bean id="user" class="com.huawei.SpringDemo2023.User" parent="templateA" >
<!-- <property name="name" value="cxk" />-->
</bean>
被注入的类
public class TestEditor {
// 需要spring注入的对象
private SpellChecker spellChecker;
public TestEditor(){
System.out.println("TestEditor-实例化:无参构造器");
}
//通过有参构造器将要注入的对象创建的责任抛出(给springioc容器来操作)
public TestEditor(SpellChecker spellChecker) {
System.out.println("TestEditor-实例化:"+spellChecker);
this.spellChecker = spellChecker;
}
public void testDI(){
this.spellChecker.aa();
}
}
要注入的类
public class SpellChecker {
public void aa(){
System.out.println("SpellChecker-AA");
}
}
spring配置-构造器注入
<!-- 准备需要注入对象的实例 -->
<bean id="spellChecker" class="com.huawei.SpringDemo2023.SpellChecker" />
<!-- 要注入实例的类 -->
<bean id="testEditor" class="com.huawei.SpringDemo2023.TestEditor">
<!-- 将要注入的实例放入TestEditor类的有参构造器的第一个参数,如果有多个参数根据标签顺序注入 -->
<!-- 当TestEditor加载时就会自动调用有参构造器,进行对象注入 -->
<constructor-arg ref="spellChecker" />
</bean>
如果你想要向一个对象传递一个引用,你需要使用 标签的 ref 属性,如果你想要直接传递值,那么你应该使用如上所示的 value 属性。
通过type属性区分类型,基础数据类型直接写名称,引用类型写全限定名
index值从0开始,如:0代表第一个参数
配置文件
<!-- 准备需要注入对象的实例 -->
<bean id="spellChecker" class="com.huawei.SpringDemo2023.SpellChecker" />
<!-- 要注入实例的类 -->
<bean id="testEditor" class="com.huawei.SpringDemo2023.TestEditor">
<!-- 调用了spellChecker对应的setter方法实现注入 -->
<property name="spellChecker" ref="spellChecker" />
</bean>
要注入的类
public class TestEditor {
private SpellChecker spellChecker;
public SpellChecker getSpellChecker() {
return spellChecker;
}
//setter方法就是提供给外部实现参数注入的方法
public void setSpellChecker(SpellChecker spellChecker) {
System.out.println("setter方法调用!");
this.spellChecker = spellChecker;
}
public void testDI(){
this.spellChecker.aa();
}
}
新旧方式对比
旧的方法:
新的方法:
<!-- namespace方法会根据被注入的类自动调用构造器注入或setter方法注入 -->
<bean id="testEditor" class="com.huawei.SpringDemo2023.TestEditor"
p:spellChecker-ref="spellChecker"
/>
当需要注入实例时才编写bean标签配置实例的注入方式
setter方法内部bean注入
构造器内部bean注入
<bean id="testEditor" class="com.huawei.SpringDemo2023.TestEditor" >
<constructor-arg name="cxk">
<bean class="com.huawei.SpringDemo2023.SpellChecker" />
</constructor-arg>
</bean>
集合的注入类似内部bean的注入
四种类型注入案例:
被注入的类
Spring 容器可以在不使用和 元素的情况下自动装配相互协作的 bean 之间的关系,这有助于减少编写一个大的基于 Spring 的应用程序的 XML 配置的数量。
下列自动装配模式,它们可用于指示 Spring 容器为来使用自动装配进行依赖注入。你可以使用元素的 autowire 属性为一个 bean 定义指定自动装配模式。
这种模式由属性名称指定自动装配。Spring 容器看作 beans,在 XML 配置文件中 beans 的 auto-wire 属性设置为 byName。然后,它尝试将它的属性与配置文件中定义为相同名称的 beans 进行匹配和连接。如果找到匹配项,它将注入这些 beans,否则,它将抛出异常。
要注入的类
public class TestEditor {
private SpellChecker cxk;
public SpellChecker getCxk() {
return cxk;
}
// byName方法只会使用setter方法实现注入
public void setCxk(SpellChecker cxk) {
this.cxk = cxk;
}
}
配置
<!-- 准备需要注入对象的实例 -->
<bean id="cxk" class="com.huawei.SpringDemo2023.SpellChecker" />
<bean id="testEditor" class="com.huawei.SpringDemo2023.TestEditor" autowire="byName"></bean>
这种模式由属性名称指定自动装配。Spring 容器看作 beans,在 XML 配置文件中 beans 的 autowire 属性设置为 byType。然后,它尝试将它的属性与配置文件中定义为相同名称的 beans 进行匹配和连接。如果找到匹配项,它将注入这些 beans,否则,它将抛出异常。
要注入的类
public class TestEditor {
private SpellChecker cxk;
public SpellChecker getCxk() {
return cxk;
}
// byType方法只会使用setter方法实现注入
public void setCxk(SpellChecker cxk) {
System.out.println("setter");
this.cxk = cxk;
}
}
配置
!-- 准备需要注入对象的实例 -->
<bean id="xxx" class="com.huawei.SpringDemo2023.SpellChecker" />
<bean id="testEditor" class="com.huawei.SpringDemo2023.TestEditor" autowire="byType"></bean>
这种模式与 byType 非常相似,但它应用于构造器参数。Spring 容器看作 beans,在 XML 配置文件中 beans 的 autowire 属性设置为 constructor。然后,它尝试把它的构造函数的参数与配置文件中 beans 名称中的一个进行匹配和连线。如果找到匹配项,它会注入这些 bean,否则,它会抛出异常。
要注入的类
public class TestEditor {
private SpellChecker cxk;
// constructor方法只会使用构造器方法实现注入
public TestEditor(SpellChecker cxk) {
System.out.println("构造器");
this.cxk = cxk;
}
}
配置
<!-- 准备需要注入对象的实例 -->
<bean id="xxx" class="com.huawei.SpringDemo2023.SpellChecker" />
<bean id="testEditor" class="com.huawei.SpringDemo2023.TestEditor" autowire="constructor"></bean>
目的:减少在xml中的复杂配置
<!-- 将所有Spring关于依赖注入的注解类实例化存放到ioc容器汇总 -->
<context:annotation-config />
必填验证注解,@Required 注解应用于 bean 属性的 setter 方法,它表明受影响的 bean 属性在配置时必须放在 XML 配置文件中,否则容器就会抛出一个 BeanInitializationException 异常。
spring版本5.3.9,注解被弃用,如果不填写,也不会报错
要注入的类
public class TestEditor {
private SpellChecker cxk;
public SpellChecker getCxk() {
return cxk;
}
// 只能用于setter方法上
@Required
public void setCxk(SpellChecker cxk) {
this.cxk = cxk;
}
}
@Autowired 注释对在哪里和如何完成自动连接提供了更多的细微的控制。
@Autowired 注释可以在 setter 方法中被用于自动连接 bean,就像 @Autowired 注释,容器,一个属性或者任意命名的可能带有多个参数的方法。
注意:1.该注解是默认带有类似@Required注解功能的,有必填验证
2.要注入的类中,提供的有参构造器尽量提供一个无参构造器,因为spring实例对象需要调用构造器,万一出现构造器必需传值而spring没有实例可以注入就会抛出UnsatisfiedDependencyException异常
@Autowired(required=false)非必填验证
// 使用setter方法注入,装配方法根据byType规则装配
@Autowired
public void setCxk(SpellChecker cxk) {
System.out.println("setter:"+cxk);
this.cxk = cxk;
}
你可以在属性中使用 @Autowired 注释来除去 setter 方法。当时使用 为自动连接属性传递的时候,Spring 会将这些传递过来的值或者引用自动分配给那些属性。
// 如果有构造器,则采用构造器的方式进行注入,如果没有则直接根据类型注入到属性中不调用setter方法
// 装配模式依旧使用bytype方法匹配
@Autowired
private SpellChecker cxk;
你也可以在构造函数中使用 @Autowired。一个构造函数 @Autowired 说明当创建 bean 时,即使在 XML 文件中没有使用 元素配置 bean ,构造函数也会被自动连接。
// 注入方式使用构造器注入,匹配规则使用byType方法匹配
@Autowired
public TestEditor(SpellChecker cxk) {
System.out.println("构造器:"+cxk);
this.cxk = cxk;
}
作用: @Autowired 注释自动装配的基础上通过bean的id或name进行选择注入
spring配置文件
<bean id="textEditor" class="com.huawei.SpringDemo2023.TestEditor"></bean>
<bean id="j1" class="com.huawei.SpringDemo2023.SpellChecker" >
<property name="name" value="高启强" />
</bean>
<bean id="j2" class="com.huawei.SpringDemo2023.SpellChecker" >
<property name="name" value="高启盛" />
</bean>
要注入的类
public class TestEditor {
@Autowired // 在byType的基础上选择
@Qualifier("j1")// 选择bean的name或id
private SpellChecker cxk;
public void test(){
System.out.println(this.cxk.getName());
}
}
public class TestEditor {
private SpellChecker cxk;
/**
* 替代了init-method配置,描述初始化回调方法
*/
@PostConstruct
public void testInit(){
System.out.println("初始化!");
}
/**
* 替代了destroy-method配置,描述销毁回调方法
*/
@PreDestroy
public void testDestory(){
System.out.println("销毁!");
}
}
通过bean的id或name进行连线装配
<!-- 将所有Spring关于依赖注入的注解类实例化存放到ioc容器汇总 -->
<context:annotation-config />
<bean id="textEditor" class="com.huawei.SpringDemo2023.TestEditor"></bean>
<bean id="j1" class="com.huawei.SpringDemo2023.SpellChecker" >
<property name="name" value="高启盛" />
</bean>
public class TestEditor {
@Resource(name="j1")
private SpellChecker cxk;
public TestEditor(){
System.out.println("构造器:无参");
}
public TestEditor(SpellChecker cxk){
System.out.println("构造器:有参"+cxk);
this.cxk = cxk;
}
public SpellChecker getCxk() {
return cxk;
}
public void setCxk(SpellChecker cxk) {
System.out.println("setter");
this.cxk = cxk;
}
}
根据类型自动装配
public class TestEditor {
// 注入的实例类型是SpellChecker类型以及子类
@Resource(type = SpellChecker.class)
private SpellChecker cxk;
public TestEditor(){
System.out.println("构造器:无参");
}
public TestEditor(SpellChecker cxk){
System.out.println("构造器:有参"+cxk);
this.cxk = cxk;
}
public SpellChecker getCxk() {
return cxk;
}
public void setCxk(SpellChecker cxk) {
System.out.println("setter");
this.cxk = cxk;
}
}
先根据类型区分,在根据名称连接
@Resource(name = "j1",type = SpellChecker.class)
private SpellChecker cxk;
@Configuration: 标识这是一个配置bean实例的类(放在类声明上)
@Bean: 标识一个返回实例对象的方法(放在方法声明上)
作用:使用类和方法替代xml配置容器的方式
注意:使用类的方法配置,spring.xml文件中就可以不用编写bean标签加载实例了
配置类
package com.huawei.SpringDemo2023;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 容器配置类
* 2023/2/10
*/
// 描述当前类是一个描述ioc容器配置的类---》等同于spring.xml配置文件
// 想要获取当前类中的bean配置需要加载当前配置类
@Configuration
public class MyConfig {
// <bean id="getSpellCheckerJ1" class="om.huawei.SpringDemo2023.SpellChecker" />
// 被添加@Bean注解的方法返回值实例将添加到ioc容器中
@Bean
public SpellChecker getSpellCheckerJ1(){
SpellChecker spellChecker = new SpellChecker();
spellChecker.setName("高启盛");
return spellChecker;
}
}
测试
/**
* 测试工具类
* 2023/2/8
*/
public class TextClass {
@Test
public void text1(){
//ApplicationContext
System.out.println("1. 容器加载");
//1. 加载配置类,初始化容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
//传统的方法通过名称获取,此时传递的是方法的名称
SpellChecker bean = (SpellChecker) context.getBean("getSpellCheckerJ1");
// 通过bean方法的返回值类型获取实例
//SpellChecker bean = context.getBean(SpellChecker.class);
System.out.println(bean.getName());
}
}
多配置类注册方法
@import 注解,导入另一个配置类的内容合并
注意:该注解只能使用在配置类声明上
配置类-1
@Configuration
@Import(MyConfig2.class)// config2导入到当前配置类
public class MyConfig {
// <bean id="getSpellCheckerJ1" class="om.huawei.SpringDemo2023.SpellChecker" />
// 被添加@Bean注解的方法返回值实例将添加到ioc容器中
@Bean
public SpellChecker getSpellCheckerJ1(){
SpellChecker spellChecker = new SpellChecker();
spellChecker.setName("高启盛");
return spellChecker;
}
}
配置类-2
@Configuration
public class MyConfig2 {
@Bean
public SpellChecker getSpellCheckerJ2(){
SpellChecker spellChecker = new SpellChecker();
spellChecker.setName("蔡徐坤");
return spellChecker;
}
}
测试
@Test
public void text1(){
//ApplicationContext
System.out.println("1. 容器加载");
//1. 加载配置类,初始化容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
//传统的方法通过名称获取,此时传递的是方法的名称
SpellChecker bean = (SpellChecker) context.getBean("getSpellCheckerJ2");
// 通过bean方法的返回值类型获取实例
//SpellChecker bean = context.getBean(SpellChecker.class);
System.out.println(bean.getName());
}
默认范围是单实例,
但是你可以重写带有 @Scope 注解的该方法
@Scope(“prototype”)多实例,IOC容器启动创建的时候,并不会创建对象放在容器在容器当中,当你需要的时候,需要从容器当中取该对象的时候,就会创建。
@Scope(“singleton”)单实例 IOC容器启动的时候就会调用方法创建对象,以后每次获取都是从容器当中拿同一个对象(map当中)。
@Scope(“request”)同一个请求创建一个实例
@Scope(“session”)同一个session创建一个实例
在每个类中有相同的业务代码,都可以使用aop解决
AOP (Aspect Orient Programming),直译过来就是 面向切面编程。AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。
为什么要使用AOP?
想象下面的场景,开发中在多个模块间有某段重复的代码,我们通常是怎么处理的?显然,没有人会靠“复制粘贴”吧。在传统的面向过程编程中,我们也会将这段代码,抽象成一个方法,然后在需要的地方分别调用这个方法,这样当这段代码需要修改时,我们只需要改变这个方法就可以了。然而需求总是变化的,有一天,新增了一个需求,需要再多出做修改,我们需要再抽象出一个方法,然后再在需要的地方分别调用这个方法,又或者我们不需要这个方法了,我们还是得删除掉每一处调用该方法的地方。实际上涉及到多个地方具有相同的修改的问题我们都可以通过 AOP 来解决。
AOP 领域中的特性术语:
通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
切点(PointCut): 可以插入增强处理的连接点。
切面(Aspect): 切面是通知和切点的结合。
引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。
织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.8.RC3</version>
</dependency>
<!-- AOP配置 -->
<aop:config>
...
</aop:config>
切面是一整个aop的独立业务逻辑,需要定一个类来描述
配置
<aop:config>
<!-- 描述一个切面(包含:连接点、通知的配置) -->
<aop:aspect id="testAspect" ref="myAspect1"></aop:aspect>
</aop:config>
<!-- 配置切面的类 -->
<bean id="myAspect1" class="com.huawei.SpringDemo2023.aop.TestAspect" />
切面类
package com.huawei.SpringDemo2023.aop;
/**
* 描述切面功能类
* 配置通知方法
* 2023/2/10
*/
public class TestAspect {
...
}
切点就是定义在哪个方法或访问哪些类时会触发aop操作的时机
切点表达式:
方法表达式以 * 号开始,标识我们不关心方法的返回值类型。然后我们指定了全限定类名和方法名。对于方法参数列表,我们使用 … 标识切点选择任意的play方法,无论该方法的入参是什么。多个匹配之间我们可以使用链接符 &&、||、!来表示 “且”、“或”、“非”的关系。但是在使用 XML 文件配置时,这些符号有特殊的含义,所以我们使用 “and”、“or”、“not”来表示。
配置案例:
<!-- AOP配置 -->
<aop:config>
<!-- 描述一个切面(包含:连接点、通知的配置) -->
<aop:aspect id="testAspect" ref="myAspect1">
<!-- 描述一个切点 -->
<aop:pointcut id="cut1" expression="execution(* com.huawei.SpringDemo2023.aop.Cat.catSay(..))" />
</aop:aspect>
</aop:config>
通知的作用:通过aop的方式,增强调用处前置、后置、返回、异常的回调功能
使用规则:
前置通知:方法调用前调用,必然调用
后置通知:方法调用后调用(返回值返回之前就调用),必然调用
异常后通知:只有切点方法异常才会触发,且出现异常后,返回后通知就不会被调用
返回后通知:只有切点方法正常返回值才会触发,如果异常就不会触发
环绕通知:一个方法可以实现前后置、异常、返回后通知,控制目标方法是否调用,改变方法的返回值,应用于复杂场景下的aop通知
使用了环绕通知,建议不要使用其他通知类型
通知类型:
通知 | 标识关键字 | 描述 |
---|---|---|
前置通知 | before | 在一个方法执行之前,执行通知。 |
后置通知 | after | 在一个方法执行之后,不考虑其结果,执行通知。 |
返回后通知 | after-returning | 在一个方法执行之后,只有在方法成功完成时,才能执行通知。 |
抛出异常后通知 | after-throwing | 在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。 |
环绕通知 | around | 在建议方法调用之前和之后,执行通知。 |
通知的回调方法属于切面的定义,需要定义在切面类中
切面类:定义通知方法
package com.huawei.SpringDemo2023.aop;
/**
* 描述切面功能类
* 配置通知方法
* 2023/2/10
*/
public class TestAspect {
/**
* 前置通知
*/
public void beforeAdvice(){
System.out.println("----1.前置通知");
}
/**
* 后置通知
*/
public void afterAdvice(){
System.out.println("----2.后置通知");
}
}
配置通知(以前置、后置通知为案例)
<!-- AOP配置 -->
<aop:config>
<!-- 描述一个切面(包含:连接点、通知的配置) -->
<aop:aspect id="testAspect" ref="myAspect1">
<!-- 描述一个切点 -->
<aop:pointcut id="cut1" expression="execution(* com.huawei.SpringDemo2023.aop.Cat.catSay(..))" />
<!-- 配置通知 -->
<!-- 1.前置通知 -->
<aop:before pointcut-ref="cut1" method="beforeAdvice" />
<!-- 2.后置通知 -->
<aop:after pointcut-ref="cut1" method="afterAdvice" />
</aop:aspect>
</aop:config>
xml配置
<!-- 3.返回后通知 returning 定义一个接收方法返回值的形参,如果方法没有返回值注入null,有返回值注入方法的返回值 -->
<aop:after-returning pointcut-ref="cut1" method="afterReturning" returning="retValue" />
切面类中通知配置
/**
* 返回后通知
* retValue: 接收方法的返回值
* 返回后通知只能得到切点方法的返回值,但是无法修改
*/
public void afterReturning(Object retValue){
System.out.println("---2.1 返回后通知");
}
xml配置
<!-- 4.异常后通知 throwing 定义一个接收异常对象的形参 -->
<aop:after-throwing pointcut-ref="cut1" method="afterThrowing" throwing="ex" />
切面配置
/**
* 异常后通知
* ex: 切点方法异常抛出后,抛出的异常对象
*/
public void afterThrowing(Throwable ex){
System.out.println(ex);
System.out.println("--2.2 异常后通知");
}
xml配置
<!-- 配置通知 -->
<aop:around pointcut-ref="cut1" method="around" />
切面类中配置的环绕通知方法
public Object around(ProceedingJoinPoint point){
System.out.println("---1.前置通知");
try {
Object obj = point.proceed();// 让切点方法执行,obj是切入点方法的返回值,如果没有返回值则返回null
System.out.println("---2.1 返回后通知");
} catch (Throwable e) {
System.out.println("---2.2异常后通知");
}
System.out.println("---2.后置通知");
return "哈哈哈哈";// 返回值返回的就是切点调用方法的返回值,可以通过自定义的方法改变返回值
}
定义切点会进入的目标类
public class Cat {
public void catSay(){
System.out.println("喵!!!!");
}
public void catSay(String name){
System.out.println("喵2!!!!"+name);
}
}
测试,当调用cat的catSay方法是否会触发aop
此时切点表达式为:execution(* com.huawei.SpringDemo2023.aop.Cat.catSay(…))
@Test
public void text1(){
//ApplicationContext
System.out.println("1. 容器加载");
//1. 加载配置类,初始化容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Cat bean = context.getBean(Cat.class);
bean.catSay();
}
使用原因:
前面的例子我们都是使用XML的bean定义来配置组件。在一个稍大的项目中,通常会有上百个组件,如果这些组件采用XML的bean定义来配置,显然会增加配置文件的体积,查找及维护起来也不太方便。
Spring2.5为我们引入了组件自动扫描机制,它可以在类路径底下寻找标注了**@Component、@Service、@Controller、@Repository注解**的类,并把这些类纳入进Spring容器中管理。
<context:component-scan base-package=“cn.itcast” />这个配置隐式注册了多个对注解进行解析处理的处理器,包括context:annotation-config/该配置注册的处理器,也就是说写了<context:component-scan base-package=“cn.itcast” />配置,就不用写context:annotation-config/配置了,此外base-package为需要扫描的包(含子包)。 在xml配置了这个标签后,spring可以自动去扫描base-pack下面或者子包下面的java文件,如果扫描到有@Component @Controller@Service等这些注解的类,则把这些类注册为bean
<!-- bean自动注入实例的扫描注解开启 -->
<!-- 扫描com.huawei.SpringDemo2023的所有子包以及类带有@Component、@Service、@Controller、@Repository的类添加实例到ioc容器 -->
<!-- 该配置自动将所有Spring关于依赖注入的注解都自动开启了 <context:annotation-config/> -->
<!-- use-default-filters属性默认为true代表自动扫描报下所有带有@Component、@Service、@Controller、@Repository的类 -->
<context:component-scan base-package="com.huawei.SpringDemo2023" />
注解说明:
一般通用组件:@Component
控制器层类:@Controller
业务实现层类:@Service
案例:
@Component
public class Cat {
public void catSay(){
System.out.println("喵!!!!");
}
public void catSay(String name){
System.out.println("喵2!!!!"+name);
}
}
从容器获取
System.out.println("1. 容器加载");
//1. 加载配置类,初始化容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Cat bean = context.getBean(Cat.class);
bean.catSay();
另外context:component-scan还提供了两个子标签(1)context:include-filter(2)context:exclude-filter在说明这两个子标签前,先说一下context:component-scan有一个use-default-filters属性,该属性默认为true,这就意味着会扫描指定包下的全部的标有@Component的类,包含子注解@Service,@Reposity等,并注册成bean
可以发现这种扫描的粒度有点太大,如果你只想扫描指定包下面的Controller,该怎么办?此时子标签context:incluce-filter
案例实现:
<context:component-scan base-package="com.huawei.*" use-default-filters="false">
<context:include-filter type="annotation"expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
注意:
这里要注意:如果加上use-default-filters="false"则默认情况下是true,可能会出现扫描到非@Controller注解的类加载为bean,所以指定扫描注解一定要加上use-default-filters="false"配置。
另外在我参与的项目中可以发现在base-package指定的包中有的子包是不含有注解了,所以不用扫描,此时可以指定context:exclude-filter来进行过滤,说明此包不需要被扫描
案例实现:
<context:component-scan base-package="com.huawei.*" use-default-filters="false">
<context:exclude-filter type="annotation"expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<context:exclude-filter>指定的不扫描
<context:include-filter>指定的扫描
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。