一、spring 的核心思想有哪些?
Spring的核心思想包括以下几个方面:
1. 轻量级和非侵入性:Spring框架采用了轻量级的设计,不需要依赖庞大的第三方库,可以很容易地集成到现有的应用中。同时,Spring框架也是非侵入性的,不强制应用程序按照特定的模式进行开发,开发者可以根据自己的需求选择使用Spring的哪些功能。
2. 控制反转(IOC):Spring框架通过控制反转的方式来管理对象之间的依赖关系。传统的开发方式中,对象之间的依赖关系由开发者手动创建和维护,而在Spring中,对象的创建和依赖关系的维护由Spring容器负责,开发者只需要通过配置文件或注解来描述对象之间的关系,Spring容器会自动完成对象的创建和依赖注入。
spring IOC 容器类的结构
最顶层的接口 BeanFactory
子接口: ApplicationContext
ClassPathXmlApplicationContext 针对类路径下的xml文件配置的方式
AnnotationConfigApplicationContext 针对纯注解式开发配置的方式
FileSystemXmlApplicationContext 针对系统路径下的xml文件配置的方式
BeanFactory 和ApplicationContext 区别
BeanFactory使用的懒加载的形式,对象在使用的时候才会创建
ApplicationContext,当程序启动的时候会直接加载配置文件创建对象 (web推荐使用)
@Test
public void test01(){
//创建Spring容器对象 ApplicationContext
ApplicationContext ac =
new ClassPathXmlApplicationContext("applicationContext.xml");
Object userDao = ac.getBean("userDao1");
System.out.println(userDao);
}
@Test
public void test02(){
//创建Spring容器对象 BeanFactory
Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
Object userDao1 = beanFactory.getBean("userDao1");
System.out.println(userDao1);
}
3. 面向切面编程(AOP):Spring框架提供了面向切面编程的支持,可以通过配置文件或注解来定义横切关注点(如日志、事务管理等),然后将这些横切关注点应用到应用程序的不同模块中,从而实现代码的解耦和重用。
4. 容器化:Spring框架提供了一个容器(ApplicationContext)来管理和组织应用程序中的对象。通过容器,可以方便地管理对象的生命周期、依赖关系和配置信息,还可以提供其他的服务,如事件发布、国际化等。
5. 集成各种开源框架:Spring框架提供了对各种开源框架的集成支持,如持久层框架(如MyBatis、Hibernate)、Web框架(如Spring MVC)、消息队列(如RabbitMQ)等。通过集成这些框架,可以方便地使用它们的功能,同时也能够享受到Spring框架提供的便利和增强功能。
总的来说,Spring的核心思想是通过控制反转和面向切面编程来解决传统开发方式中的问题,提供了一种灵活、可扩展和易于测试的开发模式,同时还提供了丰富的功能和集成支持,帮助开发者更加高效地开发应用程序。
二、在 spring 中管理 bean 的方式有哪些?bean 的生命周期是怎样的?
在Spring中,可以通过以下几种方式来管理Bean:
1. XML配置文件:通过在XML配置文件中定义Bean的配置信息,包括类名、属性值等,然后通过Spring容器来解析配置文件并创建Bean实例。
2. 注解:通过在Bean类上使用注解(如@Component、@Service、@Repository等),告诉Spring容器该类需要被管理为Bean,Spring容器会自动扫描并创建Bean实例。
3. Java配置类:通过编写Java类来配置Bean的创建和依赖关系,使用@Configuration和@Bean注解来定义Bean的配置信息,然后通过Spring容器来加载配置类并创建Bean实例。
4. 自动装配:通过在Bean之间建立依赖关系,让Spring容器自动根据依赖关系来自动装配Bean,可以通过@Autowired、@Resource等注解来实现自动装配。
Bean的生命周期如下:
1. Bean的实例化:当Spring容器加载配置文件或扫描注解时,会根据配置信息或注解来创建Bean的实例。
2. 属性注入:在Bean实例化后,Spring容器会根据配置文件或注解中的属性值来注入Bean的属性。
3. 初始化回调:如果Bean实现了InitializingBean接口或定义了初始化方法(通过@PostConstruct注解),Spring容器会在属性注入完成后调用Bean的初始化方法。
4. 使用Bean:在初始化完成后,可以使用Bean来执行相应的业务逻辑。
5. 销毁回调:如果Bean实现了DisposableBean接口或定义了销毁方法(通过@PreDestroy注解),Spring容器在关闭时会调用Bean的销毁方法。
需要注意的是,Bean的生命周期是由Spring容器来管理的,开发者无需手动调用Bean的初始化和销毁方法,只需要在Bean中实现相应的接口或注解即可。同时,Spring容器也提供了扩展点,可以通过BeanPostProcessor接口来对Bean进行自定义的初始化和销毁处理。
三、什么是依赖注入,依赖注入的方式有哪些?
依赖注入(Dependency Injection,简称DI)是指通过外部容器来管理对象之间的依赖关系,而不是由对象自己去创建或查找依赖的方式。依赖注入可以解耦对象之间的关系,降低对象之间的耦合度,提高代码的可测试性和可维护性。
依赖注入的方式有以下几种:
1. 构造函数注入(Constructor Injection):通过对象的构造函数来注入依赖。在构造对象时,通过构造函数的参数来传入依赖的对象。例如:
public class UserService {
private UserDao userDao;
public UserService(UserDao userDao) {
this.userDao = userDao;
}
}
2. Setter方法注入(Setter Injection):通过对象的Setter方法来注入依赖。在对象创建后,通过Setter方法来设置依赖的对象。例如:
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
3. 接口注入(Interface Injection):通过对象的接口方法来注入依赖。在对象创建后,通过接口方法来设置依赖的对象。例如:
public interface UserAware {
void setUserDao(UserDao userDao);
}
public class UserService implements UserAware {
private UserDao userDao;
@Override
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
4. 注解注入(Annotation Injection):通过注解来标识依赖关系,然后由容器来自动注入依赖。在对象创建后,容器会根据注解来自动注入依赖的对象。例如:
public class UserService {
@Autowired
private UserDao userDao;
}
以上是常见的依赖注入的方式,可以根据具体的需求选择合适的方式来注入依赖。无论使用哪种方式,依赖注入都能够实现对象之间的解耦和依赖管理。
四、spring 中有哪些常用的注解?@AutoWried 和 @Resource 注解有什么区别?
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.qf"/>
在Spring中,有许多常用的注解用于实现不同的功能。以下是一些常用的注解:
1. @Autowired:用于自动装配Bean的依赖关系。可以用于构造函数、Setter方法、成员变量和方法参数上。它会根据类型进行匹配,如果存在多个匹配的Bean,则可以通过@Qualifier注解指定具体的Bean。
2. @Resource:用于自动装配Bean的依赖关系。可以用于成员变量、Setter方法和方法参数上。它会根据名称进行匹配,如果存在多个匹配的Bean,则会根据容器的默认规则进行选择。
3. @Component:用于标识一个类为Spring容器管理的组件(Bean)。可以用于任何类。
4. @Service:用于标识一个类为业务逻辑层的组件(Bean)。通常用于Service类。
5. @Repository:用于标识一个类为数据访问层的组件(Bean)。通常用于DAO类。
6. @Controller:用于标识一个类为控制器(Bean)。通常用于处理请求和响应的Controller类。
7. @Configuration:用于标识一个类为配置类,配置类中可以定义Bean的创建和依赖关系。
8. @Bean:用于定义一个Bean的配置信息。通常用于@Configuration类中的方法上。
9. @Value:用于注入属性值。可以用于成员变量和方法参数上。
10. @PostConstruct:用于标识一个方法为Bean的初始化方法,在Bean的属性注入完成后调用。
11. @PreDestroy:用于标识一个方法为Bean的销毁方法,在容器关闭时调用。
@AutoWired和@Resource注解的区别如下:
1. 注入方式:@Autowired是Spring提供的注解,通过类型进行自动装配;@Resource是JavaEE提供的注解,通过名称进行自动装配。
2. 匹配规则:@Autowired默认按照类型进行匹配,如果存在多个匹配的Bean,则可以通过@Qualifier注解指定具体的Bean;@Resource默认按照名称进行匹配,如果存在多个匹配的Bean,则会根据容器的默认规则进行选择。
3. 扩展性:@Autowired是Spring提供的注解,更加灵活,可以与其他Spring注解配合使用;@Resource是JavaEE提供的注解,不支持与其他注解的配合使用。
总的来说,@Autowired是Spring推荐使用的注解,更加灵活和强大,而@Resource是JavaEE提供的注解,更加符合JavaEE的规范。在实际使用中,可以根据具体的需求选择合适的注解。
五、什么是aop,spring 是如何整合 aop 的,项目中一般使用 aop 做什么?
AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,它通过将横切关注点(如日志、事务管理、安全性等)从业务逻辑中分离出来,以模块化的方式进行管理。AOP可以在不修改原有代码的情况下,通过切面(Aspect)来实现对横切关注点的增强。
Spring框架提供了对AOP的支持,通过集成AspectJ框架,可以在Spring中使用AOP来实现横切关注点的管理。Spring的AOP支持基于代理和基于字节码的两种方式。
在Spring中整合AOP的步骤如下:
-
引入Spring AOP相关的依赖,包括spring-aop和aspectjweaver。
-
在xml 配置文件中开启 aop 注解扫描
-
<!-- 开启注解扫描 --> <context:component-scan base-package="com.qf"/> <!-- 开启AOP的注解扫描 --> <aop:aspectj-autoproxy/> <aop:config> <!-- SpringAOP的切面 --> <aop:aspect ref="advice"> <!-- SpringAOP切入点 id:切入点的唯一标识 expression:切入点表达式 --> <!-- 切入点表达式 方法的全称 public void com.qf.service.impl.UserServiceImpl.addUser(); * com.qf.service.impl.UserServiceImpl.addUser(); * com.qf.service..*.*(..); --> <aop:pointcut id="pc" expression="execution(* com.qf.service..*.*(..))"/> <!-- SpringAOP的通知配置 --> <!-- <aop:before method="before" pointcut-ref="pc"></aop:before>--> <!-- <aop:after method="after" pointcut-ref="pc"></aop:after>--> <!-- <aop:after-throwing method="throwing" pointcut-ref="pc"/>--> <!-- <aop:after-returning method="returning" pointcut-ref="pc"/>--> <aop:around method="around" pointcut-ref="pc"></aop:around> </aop:aspect> </aop:config>
-
创建切面类,即实现了切面逻辑的类。切面类通常使用@Aspect注解进行标识,同时可以使用其他注解来定义切点和增强逻辑。
-
//增强类 public class MyAdvice { // public void before(){ // System.out.println("前置通知(在目标对象的方法之前执行)"); // } // public void after(){ // System.out.println("最终通知(在目标对象的方法之后执行(有没有异常都会执行))"); // } // public void throwing(){ // System.out.println("异常通知(在目标对象的方法之后执行(如果有异常则才会执行))"); // } // public void returning(){ // System.out.println("后置通知(在目标对象的方法之后执行(如果有异常则不会执行))"); // } public Object around(ProceedingJoinPoint joinPoint){ try { System.out.println("前置通知(在目标对象的方法之前执行)"); //System.out.println("方法本身"); //执行目标对象的方法 Object o = joinPoint.proceed(); //获取到目标对象 Object target = joinPoint.getTarget(); System.out.println(target); //获取目标对象的方法 Signature signature = joinPoint.getSignature(); System.out.println(signature.getName()); System.out.println("后置通知(在目标对象的方法之后执行(如果有异常则不会执行))"); //通过调用目标对象的方法获取到返回值,并继续返回 return o; } catch (Throwable e) { e.printStackTrace(); System.out.println("异常通知(在目标对象的方法之后执行(如果有异常则才会执行))"); } finally { System.out.println("最终通知(在目标对象的方法之后执行(有没有异常都会执行))"); } return null; } }
-
配置AOP切面,将切面类和切点配置到Spring的配置文件(或者使用基于注解的配置方式)中。
-
配置Spring容器,将需要进行AOP增强的Bean配置到Spring的配置文件(或者使用基于注解的配置方式)中。
-
在代码中使用被增强的Bean,当调用被增强的方法时,AOP切面会自动被触发,执行相应的增强逻辑。
AOP专业术语
连接点(Joinpoint): 表示一切能被增强方法
切入点(Pointcut): 被增强的方法
通知、增强(Advice): 增强的功能(通知的类型:前置通知、后置通知、异常通知、最终通知、环绕通知)
目标对象(Target): 被代理对象
织入(Weaving): 将通知加入连接点的过程
代理(Proxy): 代理对象
切面(Aspect): 连接点被增强的内容称之为切面(切入点+通知)
在项目中可以使用AOP来实现日志记录、事务管理、权限控制、以及后面 springmvc 中的拦截器和异常处理等功能。
六、spring 如何管理事务?
spring 开启事务的步骤:
1、导入 spring 事务的依赖
<!-- Spring声明式事务管理依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.6</version>
</dependency>
<!-- Spring声明式事务织入依赖 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
2、配置事务管理器
<!-- 配置Spring事务管理器对象-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据源信息-->
<property name="dataSource" ref="dataSource"/>
</bean>
注意:DataSourceTransactionManager 和 SqlSessionFactoryBean 要注入同一个DataSource,否则事务控制失败!!!
3、配置Spring事务的增强类
<tx:advice id="txAdvice" transaction-manager="transactionManager" >
<!-- 配置Spring事务的增强类的信息-->
<tx:attributes>
<!--
name:Spring:事务增强类增强的方法
isolation:事务的隔离级别
propagation:事务传播行为
REQUIRED(以事务的方式运行,如有事务,加入事务,如无事务,则创建事务) 更新
SUPPORTS(有事务则以事务方式运行,没有事务以非事务方式运行) 查询
read-only:是否只读 查询true 更新false
timeout:超时时间(默认为-1表示永久等待) 设置单位为‘秒’
rollback-for:设置哪些异常回滚
no-rollback-for:设置哪些异常不回滚
增强方法的配置技巧
通配符匹配
get*
select*
find*
query*
* 其他所有方法
-->
<tx:method name="get*" isolation="DEFAULT"
propagation="SUPPORTS" read-only="true" timeout="-1"/>
<tx:method name="select*" isolation="DEFAULT"
propagation="SUPPORTS" read-only="true" timeout="-1"/>
<tx:method name="find*" isolation="DEFAULT"
propagation="SUPPORTS" read-only="true" timeout="-1"/>
<tx:method name="query*" isolation="DEFAULT"
propagation="SUPPORTS" read-only="true" timeout="-1"/>
<tx:method name="*" isolation="DEFAULT"
propagation="REQUIRED" read-only="false" timeout="-1"/>
</tx:attributes>
</tx:advice>
属性说明
isolation
隔离级别
名称 | 描述 |
---|---|
default | (默认值)(采用数据库的默认的设置) (建议) |
read-uncommited | 读未提交 |
read-commited | 读提交 (Oracle数据库默认的隔离级别) |
repeatable-read | 可重复读 (MySQL数据库默认的隔离级别) |
serialized-read | 序列化读 |
propagation
事务传播行为
名称 | 作用 |
---|---|
PROPAGATION_REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。 |
当涉及到事务嵌套(Service调用Service)时,可以设置:
supports= 不存在外部事务,则不开启新事务;存在外部事务,则合并到外部事务中。(适合查询)
REQUIRED = 不存在外部事务,则开启新事务;存在外部事务,则合并到外部事务中。 (默认值)(适合增删改)
readonly
读写性
true:只读,可提高查询效率。(适合查询)
false:可读可写。 (默认值)(适合增删改)
timeout
事务超时时间
当前事务所需操作的数据被其他事务占用,则等待。
1000:自定义等待时间1000(秒)。
-1:由数据库指定等待时间,默认值。(建议)
rollbackFor
配置回滚的异常
noRollbackFor
配置不回滚的异常
4、配置事务切面
<!-- 配置Spring切面-->
<aop:config>
<!-- 配置Spring切入点-->
<aop:pointcut id="pc" expression="execution(* com.qf.service..*.*(..))"/>
<!-- 配置Spring增强类-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
</aop:config>
使用注解开启事务的配置步骤如下:
<!-- Spring声明式事务基于注解的配置-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据源信息-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 开启Spring事务的包扫描 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
在service层的方法或者类上添加注解
注解加在类上表示所有的方法都使用事务管理
注解加在方法上仅表示当前方法使用事务管理
@Transactional(isolation = Isolation.DEFAULT,
propagation = Propagation.REQUIRED,readOnly = false,timeout = -1)