8.框架Spring
一、基本概念
Spring 是 Java EE 编程领域的一款轻量级的开源框架,由被称为“Spring 之父”的 Rod Johnson 于 2002 年提出并创立,它的目标就是要简化 Java 企业级应用程序的开发难度和周期。
导入依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.22</version>
</dependency>
二、IoC容器
在传统的 Java 应用中,一个类想要调用另一个类中的属性或方法,通常会先在其代码中通过 new Object() 的方式将后者的对象创建出来,然后才能实现属性或方法的调用。为了方便理解和描述,我们可以将前者称为“调用者”,将后者称为“被调用者”。也就是说,调用者掌握着被调用者对象创建的控制权。
但在 Spring 应用中,Java 对象创建的控制权是掌握在 IoC 容器手里的,其大致步骤如下:
- 开发人员通过 XML 配置文件、注解、Java 配置类等方式,对 Java 对象进行定义,例如在 XML 配置文件中使用 <bean> 标签、在 Java 类上使用 @Component 注解等。
- Spring 启动时,IoC 容器会自动根据对象定义,将这些对象创建并管理起来。这些被 IoC 容器创建并管理的对象被称为 Spring Bean。
- 当我们想要使用某个 Bean 时,可以直接从 IoC 容器中获取(例如通过 ApplicationContext 的 getBean() 方法),而不需要手动通过代码(例如 new Obejct() 的方式)创建。
IoC 带来的最大改变不是代码层面的,而是从思想层面上发生了“主从换位”的改变。原本调用者是主动的一方,它想要使用什么资源就会主动出击,自己创建;但在 Spring 应用中,IoC 容器掌握着主动权,调用者则变成了被动的一方,被动的等待 IoC 容器创建它所需要的对象 bean 。
这个过程在职责层面发生了控制权的反转,把原本调用者通过代码实现的对象的创建,反转给 IoC 容器来帮忙实现,因此我们将这个过程称为 Spring 的“控制反转”。
BeanFactory 是 IoC 容器的基本实现,也是 Spring 提供的最简单的 IoC 容器,它提供了 IoC 容器最基本的功能,由 org.springframework.beans.factory.BeanFactory 接口定义。
@Test
public void test1() {
DefaultListableBeanFactory factory=new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions("beans.xml");
User user= (User) factory.getBean("user");
System.out.println(user);
}
ApplicationContext 是 BeanFactory 接口的子接口,是对 BeanFactory 的扩展。ApplicationContext 在 BeanFactory 的基础上增加了许多企业级的功能,例如 AOP(面向切面编程)、国际化、事务支持等。
@Test
public void test2() {
//加载类路径xml
ApplicationContext context1=new ClassPathXmlApplicationContext();
//加载指定路径xml
ApplicationContext context2=new FileSystemXmlApplicationContext();
//加载注解
ApplicationContext context3=new AnnotationConfigApplicationContext();
//混合方式加载bean
ApplicationContext context4=new GenericApplicationContext();
}
三、Bean
Spring开发中主要是对Bean的配置,Bean的常用配置一览如下:
Bean 属性注入,简单点说就是将属性注入到 Bean 中的过程,而这属性既可以普通属性,也可以是一个对象(Bean)。Spring 主要通过以下 2 种方式实现属性注入:1.构造函数注入;2.设值注入。
构造注入:
<!--name:按变量名注入
type:按类型注入
index:按索引注入
value:注入值
ref:注入bean-->
<bean id="user" class="com.lulu.entity.User">
<constructor-arg type="java.lang.Long" value="1"/>
<constructor-arg index="1" value="lulu"/>
<constructor-arg name="age" value="20"/>
<constructor-arg name="gender" value="1"/>
<constructor-arg name="book" ref="book"/>
</bean>
设值注入:
<!--name:按变量名注入
value:注入值
ref:注入bean-->
<bean id="user" class="com.lulu.entity.User">
<property name="id" value="1"/>
<property name="name" value="lulu"/>
<property name="age" value="20"/>
<property name="gender" value="1"/>
<property name="book" ref="book"/>
</bean>
特殊类型注入:
<!--array:数组注入
list:列表注入
set:集合注入
map:键值对注入
properties:键值对注入
value:注入值
ref:注入bean-->
<bean id="user" class="com.lulu.entity.User">
<property name="strings">
<array>
<value>string</value>
</array>
</property>
<property name="list">
<list>
<ref bean="book"/>
</list>
</property>
<property name="set">
<set>
<value>set</value>
</set>
</property>
<property name="map">
<map>
<entry key="map" value="map"/>
</map>
</property>
<property name="properties">
<props>
<prop key="prop">prop</prop>
</props>
</property>
</bean>
为了简化开发,可以使用注解进行bean配置(需要指定扫描包):
@Data//lombok
@NoArgsConstructor
@AllArgsConstructor
@Component("user")//声明为普通bean,衍生 @Controller:web层bean, @Service:service层bean, @Repository:dao层bean
@Scope("prototype")//bean模式
@Lazy//延迟加载
public class User {
@Value("1")//值注入
private Long id;
@Value("lulu")
private String name;
@Value("20")
private Integer age;
@Value("1")
private Integer gender;
@Resource(name = "book",type = Book.class)//按名称或类型注入
@Autowired//按类型注入
private Book book;
@PostConstruct//初始化方法
private void postConstruct(){}
@PreDestroy//销毁前方法
private void preDestroy(){}
}
如果完全不使用xml文件进行配置,需要自定义配置类,并加入ApplicationContext:
@Configuration//声明为配置类
@ComponentScan("com.lulu.entity")//指定扫描包
public class SpringConfig {
@Bean//将方法返回对象声明为bean
public void bean(){}
}
在测试类中使用自动注入时要注意导入依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.22</version>
</dependency>
//@RunWith注解表示运行在Spring容器中,包括controller,service,dao等
@RunWith(SpringJUnit4ClassRunner.class)
//加载spring配置类
@ContextConfiguration(classes = SpringConfig.class)
public class Test1 {
}
四、AOP
Spring AOP 是 Spring 框架的核心模块之一,它使用纯 Java 实现,因此不需要专门的编译过程和类加载器,可以在程序运行期通过代理方式向目标类织入增强代码。
导入依赖:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
在配置文件中需要开启AOP命名空间:
<aop:config>
<!--配置切入点:指定类方法,切点表达式execution([修饰符] 返回值类型 包名.类名.方法(参数))-->
<aop:pointcut id="pointcut" expression="execution(void com.lulu.entity.User.sayHello())"/>
<!--配置切面:指定增强方法与切入点结合-->
<aop:aspect ref="userAdvice">
<!--前置增强-->
<aop:before method="pre" pointcut-ref="pointcut"/>
<!--后置增强-->
<aop:after method="post" pointcut-ref="pointcut"/>
<!--环绕增强-->
<aop:around method="around" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
增强方法有五种类型:
注解配置AOP需要在配置类声明@EnableAspectJAutoProxy:
@Component
@Aspect//声明为增强类
public class UserAdvice {
//配置切入点
@Pointcut("execution(void com.lulu.entity.User.sayHello())")
public void pointcut(){}
@Before("pointcut()")
public void pre(){
System.out.println("preAdvice");
}
@After("pointcut()")
public void post(){
System.out.println("postAdvice");
}
@Around("pointcut()")
public void around(){
System.out.println("aroundAdvice");
}
}
事务(Transaction)是基于关系型数据库(RDBMS)的企业应用的重要组成部分。在软件开发领域,事务扮演者十分重要的角色,用来确保应用程序数据的完整性和一致性。作为一款优秀的开源框架和应用平台,Spring 也对事务提供了很好的支持。Spring 借助 IoC 容器强大的配置能力,为事务提供了丰富的功能支持。
导入依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.22</version>
</dependency>
开启事务需要在配置类上声明@EnableTransactionManagement并配置事务管理器:
@Bean//配置数据源
public DataSource dataSource(){
DruidDataSource dataSource=new DruidDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///libmanagesystem?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai");
dataSource.setUsername("");
dataSource.setPassword("");
return dataSource;
}
@Bean//配置事务管理器
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager=new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
在需要进行事务管理的类或方法上声明@Transactional即可。@Transactional 注解包含多个属性,其中常用属性如下表。
事务属性 | 说明 |
---|---|
propagation | 指定事务的传播行为。 |
isolation | 指定事务的隔离级别。 |
read-only | 指定是否为只读事务。 |
timeout | 表示超时时间,单位为“秒”;声明的事务在指定的超时时间后,自动回滚,避免事务长时间不提交会回滚导致的数据库资源的占用。 |
rollback-for | 指定事务对于那些类型的异常应当回滚,而不提交。 |
no-rollback-for | 指定事务对于那些异常应当继续运行,而不回滚。 |