文章目录
-
- 注解
-
- @Component与@Bean的区别
- [@Autowired 和 @Resource 的区别是什么?](#@Autowired 和 @Resource 的区别是什么?)
- 使用方式:
- Bean
-
- [Bean 是线程安全的吗?](#Bean 是线程安全的吗?)
- Bean的作用域
- [Bean 的生命周期了解么?](#Bean 的生命周期了解么?)
-
- [1. Bean 实例化](#1. Bean 实例化)
- [2. 属性赋值](#2. 属性赋值)
- [3. 初始化](#3. 初始化)
- [4. Bean 销毁](#4. Bean 销毁)
- 结合代码理解Bean的生命周期
-
- [1. Bean 实例化](#1. Bean 实例化)
- [2. Bean 属性赋值](#2. Bean 属性赋值)
- [3. Bean 初始化](#3. Bean 初始化)
- [4. Bean 销毁-注册回调接口](#4. Bean 销毁-注册回调接口)
- AOP
-
- 什么是AOP
- 如何使用AOP
-
- 手写事务管理器学习AOP的使用
-
- [0. 不使用AOP的思想](#0. 不使用AOP的思想)
- 1.使用配置类AOP的思想代码如下:
- 2.注解开发实现AOP
- AOP的底层原理
注解
@Component与@Bean的区别
1. @Component 注解
@Component 注解是Spring中用于定义一个普通组件类的注解。你可以将它用在任何希望由Spring容器管理的类上。
Spring容器启动时,它会自动扫描整个类路径,寻找所有带有 @Component 注解的类,并将其实例化为Bean对象。这些Bean对象随后就可以被注入到其他组件中,实现依赖注入的功能。
此外,@Component 注解还有三个衍生注解: @Controller、 @Service 和 @Repository,它们分别用于标识控制器、业务层和数据访问层的组件。这些注解在功能上与 @Component 相同,但提供了更具体的语义,有助于我们对应用程序的不同部分进行更好的划分和组织。
2. @Bean注解
与 @Component 不同, @Bean 注解是用于在Java配置类 中定义一个Bean对象的方法 。
通常,我们会将 @Configuration 注解加在一个类上,表示这是一个配置类。在这个配置类中,我们可以使用 @Bean 注解来标记方法,这些方法将返回一个Bean对象。
Spring容器会根据这些配置来创建相应的Bean,并在整个应用程序中提供这些Bean的访问。
要注意的是,通过 @Bean 注解定义的Bean对象是通过调用被标记方法的方式创建的。这意味着我们可以在方法中进行额外的初始化操作,或者在返回Bean对象之前对其进行修改。这种灵活性使得@Bean注解在某些场景下比 @Componen t注解更加有用。
如果你只是需要一个简单的Bean对象,并且不需要进行额外的初始化或修改操作,那么@Component注解可能是一个更好的选择。因为它更简洁,且不需要手动配置。然而,如果你需要在创建Bean对象时进行额外的操作,或者需要更灵活地控制Bean的创建过程,那么@Bean注解将是一个更好的选择。
Bean注解的使用示例:
java
@Configuration
public class AppConfig {
@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
上面的代码相当于下面的 xml 配置
xml
<beans>
<bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>
下面这个例子是通过 @Component 无法实现的。
java
@Bean
public OneService getService(status) {
case (status) {
when 1:
return new serviceImpl1();
when 2:
return new serviceImpl2();
when 3:
return new serviceImpl3();
}
}
@Autowired 和 @Resource 的区别是什么?
- @Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。
- @Autowired默认的注入方式为byType(根据类型进行匹配) ,@Resource默认注入方式为 byName(根据名称进行匹配)。当一个接口存在多个实现类的情况下,@Autowired 和@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过 @Qualifier 注解来显式指定名称,@Resource可以通过 name 属性来显式指定名称。
- @Autowired 支持在构造函数、方法、字段和参数上使用。@Resource 主要用于字段和方法上的注入,不支持在构造函数或参数上使用。
使用方式:
举个例子,SmsService 接口有两个实现类: SmsServiceImpl1和 SmsServiceImpl2,且它们都已经被 Spring 容器所管理。
java
// 报错,byName 和 byType 都无法匹配到 bean
@Autowired
private SmsService smsService;
// 正确注入 SmsServiceImpl1 对象对应的 bean
@Autowired
private SmsService smsServiceImpl1;
// 正确注入 SmsServiceImpl1 对象对应的 bean
// smsServiceImpl1 就是我们上面所说的名称
@Autowired
@Qualifier(value = "smsServiceImpl1")
private SmsService smsService;
public @interface Resource {
String name() default "";
Class<?> type() default Object.class;
}
// 报错,byName 和 byType 都无法匹配到 bean
@Resource
private SmsService smsService;
// 正确注入 SmsServiceImpl1 对象对应的 bean
@Resource
private SmsService smsServiceImpl1;
// 正确注入 SmsServiceImpl1 对象对应的 bean(比较推荐这种方式)
@Resource(name = "smsServiceImpl1")
private SmsService smsService;
Bean
Bean 是线程安全的吗?
prototype 作用域下,每次获取都会创建一个新的 bean 实例,不存在资源竞争问题,所以不存在线程安全问题。singleton 作用域下,IoC 容器中只有唯一的 bean 实例,可能会存在资源竞争问题(取决于 Bean 是否有状态)。如果这个 bean 是有状态的话,那就存在线程安全问题(有状态 Bean 是指包含可变的成员变量的对象)。不过,大部分 Bean 实际都是无状态(没有定义可变的成员变量)的(比如 Dao、Service),这种情况下, Bean 是线程安全的。
对于有状态单例 Bean 的线程安全问题,常见的有两种解决办法:
- 在 Bean 中尽量避免定义可变的成员变量。
- 在类中定义一个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)
Bean的作用域
Spring 中 Bean 的作用域通常有下面几种:
- singleton : IoC 容器中只有唯一的 bean 实例。Spring 中的 bean 默认都是单例的,是对单例设计模式的应用。
- prototype : 每次获取都会创建一个新的 bean 实例。也就是说,连续 getBean() 两次,得到的是不同的 Bean 实例。
- request (仅 Web 应用可用): 每一次 HTTP 请求都会产生一个新的 bean(请求 bean),该 bean 仅在当前 HTTP request 内有效。
- session (仅 Web 应用可用) : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean(会话 bean),该 bean 仅在当前 HTTP session 内有效。
如何配置 bean 的作用域呢?
xml 方式:
xml
<bean id="..." class="..." scope="singleton"></bean>
注解方式:@Bean
java
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Person personPrototype() {
return new Person();
}
Bean 的生命周期了解么?
- 创建 Bean 的实例:Bean 容器首先会找到配置文件中的 Bean 定义,然后使用 Java 反射 API 来创建 Bean 的实例。
- Bean 属性赋值/填充:为 Bean 设置相关属性和依赖,例如@Autowired 等注解注入的对象、@Value 注入的值、setter方法或构造函数注入依赖和值、@Resource注入的各种资源。
- Bean 初始化:
如果 Bean 实现了 BeanNameAware 接口,调用 setBeanName()方法,传入 Bean 的名字。
如果 Bean 实现了 BeanClassLoaderAware 接口,调用 setBeanClassLoader()方法,传入 ClassLoader对象的实例。
如果 Bean 实现了 BeanFactoryAware 接口,调用 setBeanFactory()方法,传入 BeanFactory对象的实例。
与上面的类似,如果实现了其他 *.Aware接口,就调用相应的方法。
如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessBeforeInitialization() 方法
如果 Bean 实现了InitializingBean接口,执行afterPropertiesSet()方法。
如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。
如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessAfterInitialization() 方法。 - 销毁 Bean:销毁并不是说要立马把 Bean 给销毁掉,而是把 Bean 的销毁方法先记录下来,将来需要销毁 Bean 或者销毁容器的时候,就调用这些方法去释放 Bean 所持有的资源。
如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。
如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的 Bean 销毁方法。
也可以直接通过@PreDestroy 注解标记 Bean 销毁之前执行的方法。
如何记忆呢?
- 整体上可以简单分为四步:实例化 ---> 属性赋值 ---> 初始化 ---> 销毁。
- 初始化这一步涉及到的步骤比较多,包含 Aware 接口的依赖注入、BeanPostProcessor 在初始化前后的处理以及 InitializingBean 和 init-method 的初始化操作。
- 销毁这一步会注册相关销毁回调接口,最后通过DisposableBean 和 destory-method 进行销毁。
最后,再分享一张清晰的图解(图源:如何记忆 Spring Bean 的生命周期open in new window)。
1. Bean 实例化
一旦Spring容器获得Bean的定义,它会使用Java反射API来实例化Bean。Java反射API允许在运行时检查类、方法和字段,并在需要时动态创建对象实例。通常情况下,Spring会调用Bean类的默认构造函数来创建实例,但也支持使用工厂方法或者其他创建方式。
当Spring容器实例化Bean时,它可以根据配置使用不同的创建方式。以下是一个示例:
假设我们有一个简单的Java类 UserService,它有一个默认的无参构造函数和一个带参数的构造函数,如下所示:
java
public class UserService {
private String serviceName;
// 默认无参构造函数
public UserService() {
this.serviceName = "DefaultService";
}
// 带参数的构造函数
public UserService(String serviceName) {
this.serviceName = serviceName;
}
// 其他方法
public void execute() {
System.out.println("Executing service: " + serviceName);
}
}
现在,我们可以通过XML配置文件来告诉Spring如何实例化 UserService 类的Bean。以下是一个简化的XML配置示例 beans.xml:
xml
<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="userServiceDefault" class="com.example.UserService" />
<!-- 定义一个使用带参数构造函数实例化的Bean -->
<bean id="userServiceCustom" class="com.example.UserService">
<constructor-arg value="CustomService" />
</bean>
</beans>
2. 属性赋值
通过一个简单的例子来说明如何使用Spring Framework进行属性赋值和依赖注入。
假设我们有一个简单的Java类和它对应的Spring配置,演示如何使用populateBean方法进行属性填充和依赖注入。
- 创建一个普通的Java类
假设我们有一个简单的服务类 UserService,它依赖于 UserRepository。
java
public class UserService {
private UserRepository userRepository;
private String serviceName;
// 构造函数注入
public UserService(UserRepository userRepository, String serviceName) {
this.userRepository = userRepository;
this.serviceName = serviceName;
}
// 方法
public void processUser(String username) {
userRepository.save(username);
System.out.println(serviceName + " saved user: " + username);
}
}
- 创建 UserRepository 接口和实现类
java
public interface UserRepository {
void save(String username);
}
@Component
public class UserRepositoryImpl implements UserRepository {
@Override
public void save(String username) {
// 实现保存逻辑
System.out.println("Saving user: " + username);
}
}
- 配置 Spring Bean
使用 XML 配置文件或者注解方式配置 Spring Bean,示例中使用注解方式配置:
java
@Configuration
@ComponentScan(basePackages = "com.example.services")
public class AppConfig {
@Bean
public UserService userService() {
return new UserService(userRepository(), "User Processing Service");
}
@Bean
public UserRepository userRepository() {
return new UserRepositoryImpl();
}
}
- 使用 populateBean 方法进行属性填充
假设在某个Spring管理的容器中,我们希望手动进行属性填充,可以使用 populateBean 方法。以下是一个伪代码示例:
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MainApp {
public static void main(String[] args) {
// 创建一个 ApplicationContext
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 获取 DefaultListableBeanFactory,它是 BeanDefinition 的管理器
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
// 假设我们要手动填充属性给 UserService
UserService userService = new UserService(null, null); // 创建一个空的 UserService 实例
// 获取 UserService 对应的 BeanDefinition
BeanDefinition userServiceBeanDefinition = beanFactory.getBeanDefinition("userService");
// 使用 populateBean 方法填充属性
// 假设第二个参数 mbd 是 UserService 对应的 BeanDefinition
// 假设第三个参数 instanceWrapper 是 UserService 实例的一个包装器
populateBean("userService", userServiceBeanDefinition, new InstanceWrapper(userService));
// 现在 userService 应该已经填充了属性
userService.processUser("John");
// 关闭 Spring 应用上下文
context.close();
}
// 伪代码,模拟 populateBean 方法
private static void populateBean(String beanName, BeanDefinition mbd, InstanceWrapper instanceWrapper) {
// 实际的 populateBean 方法会根据 mbd 的配置来设置实例的属性和依赖
// 这里只是演示逻辑,实际情况下 Spring 负责这个方法的实现
UserService userService = (UserService) instanceWrapper.getWrappedInstance();
UserRepository userRepository = new UserRepositoryImpl(); // 模拟从容器中获取依赖
String serviceName = "User Processing Service"; // 模拟从容器中获取属性值
userService.setUserRepository(userRepository);
userService.setServiceName(serviceName);
}
// InstanceWrapper 类的伪代码
static class InstanceWrapper {
private Object wrappedInstance;
public InstanceWrapper(Object wrappedInstance) {
this.wrappedInstance = wrappedInstance;
}
public Object getWrappedInstance() {
return wrappedInstance;
}
}
}
解释示例:
UserService 类是一个简单的服务类,依赖于 UserRepository 和 serviceName 属性。
UserRepository 接口和 UserRepositoryImpl 类是具体的数据访问对象,实现了用户保存的逻辑。
AppConfig 类使用了 Spring 的 Java 配置方式,配置了 UserService 和 UserRepository 的 Bean。
在 MainApp 中,我们模拟了使用 populateBean 方法手动填充 UserService 的属性。实际上,Spring 在初始化时会自动完成这些操作,我们这里仅作示例。
在实际的应用中,Spring Framework会自动管理 Bean 的依赖关系和属性赋值,开发者一般不需要手动操作 populateBean 方法。
3. 初始化
在 Spring Framework 中,如果一个 Bean 实现了特定的 Aware 接口,Spring 容器在将这些 Bean 实例化并进行依赖注入时,会调用相应的 Aware 接口方法,以便将容器的信息传递给 Bean。这些 Aware 接口包括:
BeanNameAware 接口:
如果 Bean 实现了 BeanNameAware 接口,Spring 在将 Bean 实例化并设置 Bean 名称后 ,会调用其 setBeanName(String name) 方法,将 Bean 的名字作为参数传递给该方法。
java
import org.springframework.beans.factory.BeanNameAware;
public class MyBean implements BeanNameAware {
private String beanName;
@Override
public void setBeanName(String name) {
this.beanName = name;
System.out.println("Bean name is: " + name);
}
// Other methods
}
BeanClassLoaderAware 接口:
如果 Bean 实现了 BeanClassLoaderAware 接口,Spring 在实例化 Bean 并设置其类加载器后 ,会调用其 setBeanClassLoader(ClassLoader classLoader) 方法,将 ClassLoader 对象的实例作为参数传递给该方法。
java
import org.springframework.beans.factory.BeanClassLoaderAware;
public class MyBean implements BeanClassLoaderAware {
private ClassLoader classLoader;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
System.out.println("Bean's ClassLoader is: " + classLoader);
}
// Other methods
}
BeanFactoryAware 接口:
如果 Bean 实现了 BeanFactoryAware 接口,Spring 在实例化 Bean 并将其注册到 BeanFactory 后 ,会调用其 setBeanFactory(BeanFactory beanFactory) 方法,将 BeanFactory 的实例作为参数传递给该方法。
java
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
public class MyBean implements BeanFactoryAware {
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
System.out.println("BeanFactory instance: " + beanFactory);
}
// Other methods
}
这些 Aware 接口方法允许 Bean 在实例化后获取 Spring 容器的一些信息,例如 Bean 的名称、类加载器或者容器本身,从而可以根据这些信息执行特定的操作或者配置。
4. Bean 销毁
在 Spring Framework 中,Bean 的销毁过程可以通过以下几个例子来说明:
使用 @PreDestroy 注解:
java
import javax.annotation.PreDestroy;
public class MyBean {
@PreDestroy
public void preDestroy() {
// 执行销毁前的操作,比如释放资源
System.out.println("Bean is being destroyed. Performing cleanup...");
}
}
在这个例子中,preDestroy() 方法使用了 @PreDestroy 注解,Spring 容器在销毁该 Bean 之前会自动调用这个方法。你可以在这个方法中执行任何你需要在 Bean 销毁前进行的清理操作,例如释放资源或关闭连接。
配置文件中指定 destroy-method:
xml
<bean id="myBean" class="com.example.MyBean" destroy-method="cleanup">
<!-- 其他配置 -->
</bean>
java
public class MyBean {
public void cleanup() {
// 执行销毁前的操作
System.out.println("Bean is being destroyed. Performing cleanup...");
}
}
在这个例子中,配置文件指定了 destroy-method 为 cleanup,表示在 Spring 容器销毁 myBean Bean 时,会调用 cleanup() 方法执行清理操作。
实现 DisposableBean 接口:
java
import org.springframework.beans.factory.DisposableBean;
public class MyBean implements DisposableBean {
@Override
public void destroy() throws Exception {
// 执行销毁前的操作
System.out.println("Bean is being destroyed. Performing cleanup...");
}
}
在这个例子中,MyBean 类实现了 DisposableBean 接口,必须实现 destroy() 方法。Spring 容器在销毁该 Bean 时会调用 destroy() 方法执行清理逻辑。
这些例子展示了在 Spring 中如何通过不同的方式来定义和执行 Bean 的销毁过程。每种方式都有其特定的用途和适用场景,你可以根据具体需求选择最合适的方式来管理 Bean 的生命周期。
结合代码理解Bean的生命周期
java
// AbstractAutowireCapableBeanFactory.java
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 1. 实例化
BeanWrapper instanceWrapper = null;
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object exposedObject = bean;
try {
// 2. 属性赋值
populateBean(beanName, mbd, instanceWrapper);
// 3. 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// 4. 销毁-注册回调接口
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
return exposedObject;
}
1. Bean 实例化
2. Bean 属性赋值
3. Bean 初始化
java
// AbstractAutowireCapableBeanFactory.java
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 3. 检查 Aware 相关接口并设置相关依赖,允许bean意识到其所在的环境。
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
// 4. BeanPostProcessor 前置处理
// 在初始化bean (wrappedBean) 之前,先应用注册的所有BeanPostProcessor实例。调用applyBeanPostProcessorsBeforeInitialization方法来对bean进行定制化处理。
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
// 5. 若实现 InitializingBean 接口,调用 afterPropertiesSet() 方法
// 6. 若配置自定义的 init-method方法,则执行
// 这部分负责bean的初始化:如果bean实现了InitializingBean接口,会调用afterPropertiesSet()方法来完成初始化。
// 如果配置了自定义的初始化方法(例如XML配置中的init-method或者使用@PostConstruct注解的方法),会通过invokeInitMethods方法来执行。
// 如果在初始化过程中发生异常,会捕获并封装成BeanCreationException,提供详细的错误信息。
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
// 7. BeanPostProceesor 后置处理
// 在完成初始化后,再次应用BeanPostProcessor实例 (applyBeanPostProcessorsAfterInitialization)来对bean进行最终的定制化处理。
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
4. Bean 销毁-注册回调接口
java
// DisposableBeanAdapter.java
public void destroy() {
// 9. 若实现 DisposableBean 接口,则执行 destory()方法
if (this.invokeDisposableBean) {
try {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((DisposableBean) this.bean).destroy();
return null;
}, this.acc);
}
else {
((DisposableBean) this.bean).destroy();
}
}
}
// 10. 若配置自定义的 detory-method 方法,则执行
if (this.destroyMethod != null) {
invokeCustomDestroyMethod(this.destroyMethod);
}
else if (this.destroyMethodName != null) {
Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
if (methodToInvoke != null) {
invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
}
}
}
AOP
什么是AOP
如何使用AOP
手写事务管理器学习AOP的使用
0. 不使用AOP的思想
applicationContext.xml
xml
<beans>
<bean id="UserService" class="service.impl.UserServiceImpl"></bean>
</beans>
事务管理器
TranscationManagerHandler
java
public class TransactionManagerHandler {
public void begin(){
System.out.println("开启事务");
}
public void commit(){
System.out.println("提交事务");
}
public void rollback(){
System.out.println("回滚事务");
}
public void closeSession(){
System.out.println("关闭连接");
}
}
如果不用Aop的思想,想使用事务管理器的代码如下,try catch代码和我们的业务没有关系,耦合性严重。
引入Aop的概念:aop能够保证我们给某个方法添加事务无需改动方法内的代码。而且可以只写一次,之后进行配置便可以指定给哪个方法加事务管理器
UserServiceImpl
java
public class UserServiceImpl implements UserService {
private TransactionManagerHandler tx = new TransactionManagerHandler();
public void insert(){
try {
tx.begin();
System.out.println("调用dao层insert()");
}
catch (Exception e){
tx.rollback();
}
finally {
tx.closeSession();
}
}
}
1.使用配置类AOP的思想代码如下:
UserServiceImpl
java
public class UserServiceImpl implements UserService {
public void insert(){
System.out.println("调用dao层insert()");
}
}
applicationContext.xml
xml
<beans>
<bean id="UserService" class="service.impl.UserServiceImpl"></bean>
<bean id="TranctionManager" class="service.TranctionManagerHandler"></bean>
<aop:config>
<aop:aspect ref="TranctionManager">
<aop:pointcut id="pt" expression="execution(public void service.impl.UserServiceImpl.insert())"></aop:pointcut>
<aop:before method="begin" pointcut-ref="pt"/>
<aop:after-returning method="commit" pointcut-ref="pt" />
<aop:after-throwing methhod="rollback" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
</beans>
- 切面: 拦截处理类,这里就是事务管理器类 <apo:aspect
- 切入点:拦截规则 就绪、后置、异常、最终 <PointCut
- 连接点:具体被拦截到的方法,这里就是insert方法
- 通知:在不同场景下拦截的功能 <before,after
- 织入:由spring完成,切面
另一种解释:
目标(Target):被通知的对象
代理(Proxy):项目表对象应用通知之后创建的代理对象
连接点(JoinPoint):目标对象的所属类中,定义的所有方法均为连接点
切入点(PointCut):被切面拦截/增强的连接点(切入点一定是连接点,连接点不一定是切入点)
通知(Advice):增强的逻辑/代码,也即拦截到目标对象
2.注解开发实现AOP
使用注解开发AOP就可以把xml删除掉了
事务管理器
TranscationManagerHandler
java
@Controller
@Aspect
public class TransactionManagerHandler {
// 切入点
@Pointcut("execution(public void service.impl.UserServiceImpl.insert()")
public void pointcut(){}
@Before("pointcut()")
public void begin(){System.out.println("开启事务");}
@AfterReturning("pointcut()")
public void commit(){System.out.println("提交事务");}
@AfterThrowing("pointcut()")
public void rollback(){System.out.println("回滚事务");}
@After("pointcut()")
public void closeSession(){System.out.println("关闭连接");}
}
SpringConfig
java
@Configuration
@ComponentScan("service")
@EnableAspectJAutoProxy
public class SpringConfig{
}
UserServiceImpl
java
@Service
public class UserServiceImpl implements UserService {
private TransactionManagerHandler tx = new TransactionManagerHandler();
public void insert(){
System.out.println("调用dao层insert()");
}
}