🏆作者简介,普修罗双战士,一直追求不断学习和成长,在技术的道路上持续探索和实践。
🏆多年互联网行业从业经验,历任核心研发工程师,项目技术负责人。
🎉欢迎 👍点赞✍评论⭐收藏
🔎 SpringBoot 领域知识 🔎
链接 | 专栏 |
---|---|
SpringBoot 专业知识学习一 | SpringBoot专栏 |
SpringBoot 专业知识学习二 | SpringBoot专栏 |
SpringBoot 专业知识学习三 | SpringBoot专栏 |
SpringBoot 专业知识学习四 | SpringBoot专栏 |
SpringBoot 专业知识学习五 | SpringBoot专栏 |
SpringBoot 专业知识学习六 | SpringBoot专栏 |
SpringBoot 专业知识学习七 | SpringBoot专栏 |
SpringBoot 专业知识学习八 | SpringBoot专栏 |
SpringBoot 专业知识学习九 | SpringBoot专栏 |
SpringBoot 专业知识学习十 | SpringBoot专栏 |
SpringBoot 专业知识学习十一 | SpringBoot专栏 |
SpringBoot 专业知识学习十二 | SpringBoot专栏 |
SpringBoot 专业知识学习十三 | SpringBoot专栏 |
SpringBoot 专业知识学习十四 | SpringBoot专栏 |
SpringBoot 专业知识学习十五 | SpringBoot专栏 |
SpringBoot 专业知识学习十六 | SpringBoot专栏 |
SpringBoot 专业知识学习十七 | SpringBoot专栏 |
SpringBoot 专业知识学习十八 | SpringBoot专栏 |
SpringBoot 专业知识学习十九 | SpringBoot专栏 |
SpringBoot 专业知识学习二十 | SpringBoot专栏 |
文章目录
- 🔎 Java 注解 @Component 学习(5)
- 🍁 41、在 Spring 中,如何通过 @Component 注解定义一个切入点(Pointcut)?
- 🍁 42、@Component 注解的 autowireCandidate 属性的作用是什么?
- 🍁 43、@Component 注解和 @Import 注解有什么关系?
- 🍁 44、在 Spring 中,是否可以通过 @Component 注解注入一个原始类型的依赖?
- 🍁 45、@Component 注解的 primary 属性的作用是什么?
- 🍁 46、@Component 注解是否支持循环依赖?
- 🍁 47、在 Spring 中,可以通过 @Component 注解实现动态代理吗?
- 🍁 48、@Component 注解和 @Qualifier 注解的作用有何区别?
- 🍁 49、在 Spring 中,是否可以通过 @Component 注解注入一个集合类型的依赖?
- 🍁 50、@Component 注解的 initMethod 和 destroyMethod 属性的作用是什么?
🔎 Java 注解 @Component 学习(5)
🍁 41、在 Spring 中,如何通过 @Component 注解定义一个切入点(Pointcut)?
在 Spring 中,定义切入点(Pointcut)是通过 @Pointcut
注解来实现的。而 @Pointcut
注解通常与 @Aspect
注解一起使用,在切面(Aspect)类中定义切入点。
不过,可以通过 @Component
注解来定义一个切面(Aspect)类,并在该类中定义切入点。具体步骤如下:
1.在类上添加 @Component
注解,并使用 @Aspect
注解表示这个类是一个切面类。
@Aspect
@Component
public class MyAspect {
//定义切入点和切面方法
}
2.在类中定义一个方法,并使用 @Pointcut
注解来定义切入点。该方法的访问修饰符可以是 public
、private
等任意访问修饰符,方法体可以为空。
@Aspect
@Component
public class MyAspect {
@Pointcut("execution(* com.example.somepackage.*.*(..))")
private void myPointcut() {
//空方法体,只是为了定义切入点名称
}
}
在上述示例中,我们定义了名为 myPointcut
的切入点,它匹配所有 com.example.somepackage
包下的类的所有方法。
🍁 42、@Component 注解的 autowireCandidate 属性的作用是什么?
@Component
注解的 autowireCandidate
属性用于控制 Spring 容器在自动装配时,是否将该 Bean 定义作为自动装配的候选者。
默认情况下,所有标记了 @Component
注解的 Bean 都会作为自动装配的候选者,即如果有其他 Bean 中存在与该 Bean 的依赖类型匹配的 Bean,则该 Bean 将被自动装配。
而 autowireCandidate
属性可以控制 Bean 是否参与自动装配的候选者的筛选过程,它的取值类型是 boolean
,默认值为 true
。
具体来讲,当 autowireCandidate
属性被设置为 false
时,该 Bean 将不会被自动装配的候选者,即如果有其他 Bean 中存在与该 Bean 的依赖类型匹配的 Bean,也不会自动装配该 Bean。
以下是示例代码:
@Component
public class MyBean {
// ... 省略其他属性和方法
@Autowired
@Qualifier("anotherBean") // 使用 Qualifier 指定注入的 Bean 名称为 "anotherBean"
@Value("${some.prop}") // 使用 Value 注入配置属性的值
@NonNull // 使用 Lombok 提供的注解标注参数不能为空
public MyBean(@NonNull AnotherBean anotherBean, @Value("${some.prop}") String propValue) {
// ... 构造方法实现
}
// ... 省略其他属性和方法
}
在上述代码中,我们使用了 @Autowired
注解来标注构造方法的参数 anotherBean
,这告诉 Spring 容器,需要自动装配一个与 AnotherBean
类型相同的 Bean,并使用名为 “anotherBean” 的 Bean。
此外,我们还使用了 @Value
注解来注入一个配置属性的值,并使用了 @NonNull
注解来保障参数的非空性。
需要注意的是,@Autowired
注解具有默认的 required
属性为 true
,这意味着如果没有找到与该参数类型匹配的 Bean,或找到的 Bean 的实例数不等于 1,那么 Spring 将会抛出一个异常。如果希望避免出现这种情况,可以将 required
属性设置为 false
。
🍁 43、@Component 注解和 @Import 注解有什么关系?
@Component
注解和 @Import
注解是 Spring 中两个不同的注解,它们在功能上有一些不同,但也存在一定的关联。
-
@Component
注解是 Spring 提供的一个通用的注解,用于将一个类标识为一个可管理的组件(Bean),让 Spring 容器自动扫描并将其实例化。@Component
注解通常与@Autowired
、@Qualifier
、@Value
等注解配合使用,用于实现依赖注入、属性注入等功能。 -
@Import
注解用于手动导入其他的配置类或配置组件(Bean)。通过@Import
注解可以在配置类中引入其他的配置类,从而将其所定义的 Bean 纳入到当前应用上下文中。同时,@Import
注解可以与@Configuration
注解一起使用,用于声明该类是一个配置类。
关于两者的关系,可以从以下两个方面来说明:
-
@Import
可以在配置类中引入使用了@Component
注解的类,将其实例化为 Bean 并纳入到 Spring 容器中。通过这种方式,我们可以在配置类中集中管理所有的@Component
注解标注的组件。 -
@Import
还可以在配置类中引入其他的配置类,通过组合和导入其他的配置类,我们可以更加灵活地管理和组织项目中的 Bean。
下面是一个示例,展示了 @Component
和 @Import
的关系:
@Configuration
@Import({MyComponent1.class, MyComponent2.class, MyConfig.class})
public class AppConfig {
// 配置类的定义
}
在上述示例中,AppConfig
是一个配置类,通过 @Import
注解导入了 MyComponent1
、MyComponent2
和 MyConfig
这三个类。其中,MyComponent1
和 MyComponent2
可能是使用了 @Component
注解的类,通过 @Import
注解将其纳入到应用上下文中,让 Spring 容器管理它们。
🍁 44、在 Spring 中,是否可以通过 @Component 注解注入一个原始类型的依赖?
在 Spring 中,是不支持通过 @Component
注解直接注入一个原始类型的依赖的,因为原始类型无法作为 Bean 注册到 Spring 容器中,Spring 只会将通过 @Component
注解标注的类作为 Bean 进行管理。
如果需要注入一个原始类型的依赖,可以考虑以下两种方式:
1.通过 @Value
注解注入原始类型的依赖:
@Component
public class MyComponent {
@Value("${myProp}") // 使用 @Value 注解注入原始类型的依赖
private int myProp;
// ...
}
在上述示例中,使用 @Value
注解注入了一个原始类型的依赖 myProp
,它的值将从 Spring 环境中获取。
2.通过一个 @Configuration
类将原始类型的依赖注入为 Bean:
@Configuration
public class MyAppConfig {
@Bean
public int myInt() {
return 42; // 返回一个 int 类型的值
}
}
在上述示例中,将一个原始类型的依赖 42
注入为一个 Spring Bean myInt
,并通过一个 @Configuration
类将其声明为一个配置类,从而引入到 Spring 环境中。
需要注意的是,通过这种方式注入的原始类型依赖不会管理生命周期,因为它们不是标准的 Bean(没有通过 @Component
注解标注),无法交由 Spring 容器管理其生命周期。
🍁 45、@Component 注解的 primary 属性的作用是什么?
在 Spring 中,@Component
注解的 primary
属性用于指定一个 Bean 是否为首选(Primary)的候选者。
当存在多个同类型的 Bean 候选者时,Spring 默认会抛出一个 NoUniqueBeanDefinitionException
异常,表示无法确定要注入哪个 Bean。这种情况下,可以使用 @Primary
注解或 primary
属性来解决这个问题。
具体来说,primary
属性可以被用于 @Component
、@Service
、@Repository
等注解。
下面是一个示例:
@Component
@Primary
public class MyComponent1 implements MyInterface {
// ...
}
@Component
public class MyComponent2 implements MyInterface {
// ...
}
@Autowired
private MyInterface myInterface;
在上述示例中,有两个实现了 MyInterface
接口的 @Component
注解标注的类:MyComponent1
和 MyComponent2
。通过给 MyComponent1
添加 @Primary
注解,我们可以将其指定为首选的 Bean。这样,当进行依赖注入时,如果没有显式指定要注入的 Bean,Spring 将选择 MyComponent1
作为首选的候选者进行注入。
需要注意的是,如果存在多个首选的 Bean,那么与 @Primary
注解相比,primary
属性具有更高的优先级。
🍁 46、@Component 注解是否支持循环依赖?
Spring 框架默认支持通过 @Autowired
进行依赖注入时的循环依赖,但是对于 @Component
注解本身是否支持循环依赖是有一些限制的。
具体来说,在默认情况下,@Component
注解是支持循环依赖的,但是有以下几个限制:
-
循环依赖只支持通过构造函数进行依赖注入,不支持通过 Setter 方法进行依赖注入。
-
循环依赖需要剥离开发者手动进行处理,即开发者需要通过限制 Bean 的依赖链长度来避免循环依赖导致的死循环和栈溢出等问题。
-
循环依赖需要依赖于 Bean 的作用域,如果 Bean 是单例作用域,则可以通过使用
@Lazy
注解或通过使用ObjectFactory
、ObjectProvider
、Provider
等方式进行解决。如果 Bean 是原型作用域,则可以通过使用@Autowired
注解将依赖注入到方法参数中来解决。
需要注意的是,虽然 Spring 默认支持循环依赖,但是循环依赖会增加程序的复杂度和难度,应该尽量避免。在实际开发中,如果出现了循环依赖的情况,建议优先考虑调整依赖关系,使其不出现循环依赖。
🍁 47、在 Spring 中,可以通过 @Component 注解实现动态代理吗?
在 Spring 中,可以通过 @Component
注解结合其他相关注解,如 @Aspect
和 @EnableAspectJAutoProxy
,来实现动态代理。
首先,使用 @Component
注解将目标类(被代理的类)声明为一个 Spring Bean。在目标类的方法上,使用 @Before
、@After
、@Around
等注解来定义切面逻辑。同时,需要在配置类上使用 @EnableAspectJAutoProxy
注解启用自动代理功能。
下面是一个示例:
@Aspect
@Component
public class MyAspect {
@Before("execution(* com.example.MyClass.myMethod(..))")
public void beforeAdvice() {
System.out.println("Before advice.");
}
}
@Component
public class MyClass {
public void myMethod() {
System.out.println("myMethod");
}
}
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
// 配置类
}
在上述示例中,MyAspect
类使用了 @Aspect
和 @Component
注解,将其声明为一个切面和 Spring Bean。MyClass
类被标注为 @Component
,也成为一个 Spring Bean。MyAspect
类中的 beforeAdvice
方法使用了 @Before
注解,表示在目标方法执行之前执行切面逻辑。
在配置类 AppConfig
上使用了 @EnableAspectJAutoProxy
注解,启用了基于 AspectJ 的自动代理功能。
当 Spring 在运行时扫描到这些注解时,会自动生成一个代理类,用于拦截被 @Aspect
注解标记的切面逻辑,并将其应用到目标类的方法上。
需要注意的是,动态代理是针对接口的,默认情况下 Spring 使用 JDK 动态代理来实现。如果目标类没有实现接口,则 Spring 将使用 CGLIB 动态代理。
🍁 48、@Component 注解和 @Qualifier 注解的作用有何区别?
@Component
和 @Qualifier
是 Spring 框架中常用的注解,具有不同的作用和用途。
@Component
注解是用于定义一个 Bean 实例,被注解的类会被 Spring 容器扫描并创建成一个 Bean。通常,我们使用 @Component
注解来定义 Service、Repository、Controller 等组件类。
@Qualifier
注解是用于指定一个 Bean 实例的名称。当 Spring 容器中存在多个同类型的 Bean 实例时,通过 @Qualifier
注解可以指定使用哪一个 Bean 实例。通常,我们在使用 @Autowired
自动注入时,配合 @Qualifier
注解来指定注入的 Bean 实例。
例如:
@Component
@Qualifier("myService")
public class MyServiceImpl implements MyService {
// ...
}
@Service
public class BusinessService {
@Autowired
@Qualifier("myService")
private MyService myService;
// ...
}
上面的例子中,我们定义了一个 MyServiceImpl
类,并使用 @Qualifier("myService")
注解指定了该 Bean 实例的名称为 “myService”。在 BusinessService
类中,我们使用 @Autowired
和 @Qualifiter("myService")
注解将 myService
Bean 自动注入到 myService
字段中。
需要注意的是,@Qualifier
注解只有在 Spring 容器中存在多个同类型的 Bean 实例时才有意义。如果只存在一个同类型的 Bean 实例,不需要使用 @Qualifier
注解。
注解 | 作用 | 使用场景 |
---|---|---|
@Component | 定义一个 Bean 实例 | Service、Repository、Controller 等组件类 |
@Qualifier | 指定一个 Bean 实例的名称 | 当容器中存在多个同类型的 Bean 实例时,用于指定使用哪一个 Bean 实例 |
简单来说,@Component
注解用于定义一个 Bean 实例,而 @Qualifier
注解用于指定一个 Bean 实例的名称,用于区分多个同类型的 Bean 实例。
🍁 49、在 Spring 中,是否可以通过 @Component 注解注入一个集合类型的依赖?
在 Spring 中可以通过 @Component
注解来注入一个集合类型的依赖。
Spring 支持将多个相同类型的 Bean 实例注入到一个集合类型的字段或参数中。可以使用 @Autowired
注解结合 @Qualifier
注解来完成这个过程。
下面是一个示例:
@Component
public class MyServiceImpl1 implements MyService {
// ...
}
@Component
public class MyServiceImpl2 implements MyService {
// ...
}
@Service
public class BusinessService {
@Autowired
private List<MyService> myServices;
// ...
}
在上面的示例中,我们定义了两个实现了 MyService
接口的类 MyServiceImpl1
和 MyServiceImpl2
并标记为 @Component
注解。接着,在 BusinessService
类中,我们使用 @Autowired
注解并将 List<MyService>
类型的字段 myServices
注入。
这样,Spring 会将所有实现了 MyService
接口的 Bean 实例注入到 myServices
字段中,并以集合的形式提供给我们使用。我们可以在 BusinessService
中遍历或使用集合中的元素。
需要注意的是,如果没有找到任何符合条件的 Bean 实例,集合类型的字段将会是空集合(而不是 null
)。
🍁 50、@Component 注解的 initMethod 和 destroyMethod 属性的作用是什么?
@Component
注解的 initMethod
和 destroyMethod
属性用于指定在 Bean 初始化和销毁时执行的方法。
-
initMethod
属性:用于指定在 Bean 初始化完成后调用的方法。该方法可以进行一些初始化操作,例如数据加载、资源初始化等。需要注意的是,被指定的方法不能有任何参数,且返回类型为void
。 -
destroyMethod
属性:用于指定在 Bean 销毁前调用的方法。该方法可以进行一些清理操作,例如资源释放、数据库连接关闭等。需要注意的是,被指定的方法不能有任何参数,且返回类型为void
。
示例:
@Component(initMethod = "init", destroyMethod = "cleanup")
public class MyService {
public void init() {
// 初始化操作
}
public void cleanup() {
// 清理操作
}
}
在上面的示例中,我们使用 @Component
注解并通过 initMethod
和 destroyMethod
属性分别指定了 init
和 cleanup
方法作为 Bean 的初始化方法和销毁方法。在 Spring 容器启动时,会先调用 init
方法进行初始化,当容器关闭时,会调用 cleanup
方法进行清理。
需要注意的是,initMethod
和 destroyMethod
属性只对 singleton 作用域的 Bean 起作用。对于 prototype 作用域的 Bean,则不会调用销毁方法。
另外,还可以使用 @PostConstruct
和 @PreDestroy
注解来代替 initMethod
和 destroyMethod
属性,它们也具有相同的作用。