Spring 基于注解装配Bean

本文介绍了Spring基于注解的配置,从Spring 2.5开始可用注解配置依赖注入,取代XML。详细说明了创建Bean的注解,如@Component及其衍生注解;还阐述了依赖注入,包括普通值注入、引用值注入,以及生命周期和作用域的注解使用,并给出了测试情况。

Spring 基于注解的配置

从 Spring 2.5 开始就可以使用注解来配置依赖注入。而不是采用 XML 来描述一个 bean 连线,你可以使用相关类,方法或字段声明的注解,将 bean 配置移动到组件类本身。

  • 注解:就是一个类,使用@注解名称
  • 开发中:使用注解 取代 xml配置文件。

创建Bean

@Component取代<bean class="">
@Component(“id”) 取代 <bean id="" class="">

web开发,提供3个@Component注解衍生注解(功能一样)取代<bean class="">

  • @Repository :dao层
  • @Service:service层
  • @Controller:web层

注解使用前提,添加命名空间,让spring扫描含有注解类

  • 配置
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       					   http://www.springframework.org/schema/beans/spring-beans.xsd
       					   http://www.springframework.org/schema/context
       					   http://www.springframework.org/schema/context/spring-context.xsd">
    
    <!-- 组件扫描,扫描含有注解的类 -->
    <context:component-scan base-package="com.cc.study.annotation"></context:component-scan>


</beans>
  • schema命名空间
    在这里插入图片描述
  • User
@Component("userId")
public class User {
    private String username;
    private Address address;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

  • 测试
 @Test
    public void demo01(){
        String xmlPath = "annotation.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        User user = (User) applicationContext.getBean("userId");
        System.out.println(user);
    }

结果发现报错了,报错如下:

java.lang.IllegalArgumentException
	at org.springframework.asm.ClassReader.<init>(Unknown Source)
	at org.springframework.asm.ClassReader.<init>(Unknown Source)
	at org.springframework.asm.ClassReader.<init>(Unknown Source)
	at org.springframework.core.type.classreading.SimpleMetadataReader.<init>(SimpleMetadataReader.java:52)
	at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:80)
	at org.springframework.core.type.classreading.CachingMetadataReaderFactory.getMetadataReader(CachingMetadataReaderFactory.java:101)
	at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:76)
	at org.springframework.context.annotation.ConfigurationClassParser.getImports(ConfigurationClassParser.java:298)
	at org.springframework.context.annotation.ConfigurationClassParser.getImports(ConfigurationClassParser.java:300)
	at org.springframework.context.annotation.ConfigurationClassParser.getImports(ConfigurationClassParser.java:300)
	at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:230)
	at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:153)
	at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:130)
	at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:285)
	at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:223)
	at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:630)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:461)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
	at com.cc.study.annotation.TestAnnotation.demo01(TestAnnotation.java:16)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

然后我试了一下把Spring的版本改成4.0,把JDK改为1.8即可

<dependencies>
        <!-- 4个核心(beans、core、context、expression) -->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.2.0.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.2.0.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.2.0.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-expression -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>4.2.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.7</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

测试结果:
在这里插入图片描述

依赖注入

依赖注入,给私有字段设置,也可以给setter方法设置

普通值注入

使用@Value

  • User
@Component("userId")
public class User {
    @Value("Kevin")
    private String username;
    private Address address;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}
  • 测试
  @Test
    public void demo02(){
        String xmlPath = "annotation.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        User user = (User) applicationContext.getBean("userId");
        System.out.println(user.getUsername());
    }

在这里插入图片描述

引用值注入

方式1:按照【类型】注入
@Autowired

  • Address
@Component
public class Address {
    @Value("北京")
    private String addr;
    @Value("112")
    private String tel;

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    public String getTel() {
        return tel;
    }

    public void setTel(String tel) {
        this.tel = tel;
    }
}

  • User
@Component("userId")
public class User {
    @Value("Kevin")
    private String username;
    @Autowired
    private Address address;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}
  • 测试
 @Test
    public void demo03(){
        String xmlPath = "annotation.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        User user = (User) applicationContext.getBean("userId");
        System.out.println(user.getUsername());
        System.out.println(user.getAddress().getAddr());
        System.out.println(user.getAddress().getTel());
    }

在这里插入图片描述

方式2:按照【名称】注入1
@Autowired
@Qualifier(“名称”)

  • Address
@Component("addressId")
public class Address {
    @Value("北京")
    private String addr;
    @Value("112")
    private String tel;

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    public String getTel() {
        return tel;
    }

    public void setTel(String tel) {
        this.tel = tel;
    }
}
  • User
@Component("userId")
public class User {
    @Value("Kevin")
    private String username;
    @Autowired
    @Qualifier("addressId")
    private Address address;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}
  • 测试
 @Test
    public void demo03(){
        String xmlPath = "annotation.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        User user = (User) applicationContext.getBean("userId");
        System.out.println(user.getUsername());
        System.out.println(user.getAddress().getAddr());
        System.out.println(user.getAddress().getTel());
    }

在这里插入图片描述

方式3:按照【名称】注入2
@Resource(name=“名称”)

  • User
@Component("userId")
public class User {
    @Value("Kevin")
    private String username;

    @Resource(name = "addressId")
    private Address address;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}
  • 测试
 @Test
    public void demo03(){
        String xmlPath = "annotation.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        User user = (User) applicationContext.getBean("userId");
        System.out.println(user.getUsername());
        System.out.println(user.getAddress().getAddr());
        System.out.println(user.getAddress().getTel());
    }

在这里插入图片描述

生命周期

初始化:@PostConstruct
销毁:@PreDestroy

  • User
@Component("userId")
public class User {
    @Value("Kevin")
    private String username;

    @Resource(name = "addressId")
    private Address address;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @PostConstruct
    public void init(){
        System.out.println("初始化");
    }
    @PreDestroy
    public void destroy(){
        System.out.println("销毁");
    }
}
  • 测试
 @Test
    public void demo04(){
        String xmlPath = "annotation.xml";
        AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        User user = (User) applicationContext.getBean("userId");
        System.out.println(user.getUsername());
        System.out.println(user.getAddress().getAddr());
        System.out.println(user.getAddress().getTel());
        applicationContext.close();
    }

在这里插入图片描述

作用域

@Scope(“prototype”) 多例

  • User
@Component("userId")
@Scope("prototype")
public class User {
    @Value("Kevin")
    private String username;

    @Resource(name = "addressId")
    private Address address;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @PostConstruct
    public void init(){
        System.out.println("初始化");
    }
    @PreDestroy
    public void destroy(){
        System.out.println("销毁");
    }
}

  • 测试
 @Test
    public void demo05(){
        String xmlPath = "annotation.xml";
        AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        User user1 = (User) applicationContext.getBean("userId");
        User user2 = (User) applicationContext.getBean("userId");
        System.out.println(user1);
        System.out.println(user2);
    }

在这里插入图片描述

<think>好的,我需要帮助用户了解Spring框架中基于注解配置Bean装配Bean的最佳实践。首先,我应该回顾一下用户提供的引用内容,确保回答准确。 用户提到的引用[1]区分了配置Bean装配Bean配置Bean是将Bean注册到IoC容器,而装配Bean是处理Bean之间的依赖注入。引用[2]和[3]给出了具体的配置示例,比如使用@Configuration和@Bean配置,以及@ComponentScan进行组件扫描。 接下来,我需要按照用户的要求,结构清晰地分步骤解释最佳实践。可能需要分成配置Bean装配Bean两部分,每部分列出常用的注解,并结合代码示例说明。例如,配置Bean可以使用@Component、@Repository、@Service、@Controller等,而装配Bean则用@Autowired或@Resource。 还要注意代码示例的正确性,比如在Java配置类中使用@Configuration和@Bean,或者在组件扫描时使用@ComponentScan。同时,需要提到最佳实践,如明确包路径、优先使用构造函数注入等。 最后,生成相关问题,确保问题与主题相关,比如关于条件装配、Java配置与XML配置的区别,或者解决依赖冲突的方法。需要确保问题覆盖用户可能感兴趣的扩展内容。 需要检查是否所有数学表达式都正确使用$...$或$$...$$格式,但这个问题是关于Spring的,可能涉及较少数学内容,但如果有示例中的表达式,比如在说明某些原理时,可能需要使用。不过根据用户的问题,可能不需要数学公式,所以这部分可能可以忽略。 最后,确保回答使用中文,引用标识自然添加,比如在提到组件扫描时引用[3],在Java配置示例时引用[2]。</think>### Spring框架中基于注解配置Bean装配Bean的最佳实践 #### 一、配置Bean:将Bean注册到IoC容器 配置Bean的核心是**通过注解标记类,使其被Spring扫描并加载到容器中**。以下是常用注解及实践方法: 1. **基础组件注解** - `@Component`:通用注解,标记任意类为Spring组件[^3]。 - 衍生注解(语义化分类): - `@Repository`:用于数据访问(DAO) - `@Service`:用于服务 - `@Controller`:用于Web控制 **示例**: ```java @Service public class UserService { // 业务逻辑 } ``` 2. **Java显式配置** - 使用`@Configuration`标记配置类,配合`@Bean`方法显式定义Bean[^2]。 **示例**: ```java @Configuration public class AppConfig { @Bean public DataSource dataSource() { return new HikariDataSource(); // 返回需要管理的Bean实例 } } ``` 3. **组件扫描** - 使用`@ComponentScan`指定包路径,Spring会自动扫描并注册Bean[^3]。 **最佳实践**: ```java @Configuration @ComponentScan("com.example.service") // 明确限定扫描范围,避免性能浪费 public class AppConfig {} ``` --- #### 二、装配Bean:依赖注入(DI) 装配Bean的核心是**通过注解实现Bean之间的依赖关系自动注入**,常用方式如下: 1. **字段/构造函数注入** - `@Autowired`:自动按类型注入,优先使用构造函数注入以提高可测试性和不可变性[^1]。 **示例**: ```java @Service public class OrderService { private final UserService userService; @Autowired // 可省略(Spring 4.3+支持隐式构造函数注入) public OrderService(UserService userService) { this.userService = userService; } } ``` 2. **限定符与条件装配** - `@Qualifier`:按名称指定Bean,解决同一类型多个实现的问题。 - `@Primary`:标记优先注入的Bean。 **示例**: ```java @Bean @Primary public Cache redisCache() { return new RedisCache(); } @Bean public Cache localCache() { return new LocalCache(); } @Autowired @Qualifier("localCache") // 明确指定注入localCache private Cache cache; ``` 3. **简化装配注解** - `@Value`:注入简单类型或配置文件属性。 - `@Resource`:按名称注入(JSR-250标准)。 --- #### 三、最佳实践总结 1. **配置Bean**: - 优先使用组件扫描,但需明确指定包路径(如`@ComponentScan("com.example")`)[^3]。 - 第三方库的Bean使用`@Configuration` + `@Bean`显式配置。 2. **装配Bean**: - 强制依赖使用**构造函数注入**,可选依赖使用Setter注入。 - 多实现时通过`@Qualifier`或`@Primary`消除歧义[^1]。 3. **代码可维护性**: - 避免滥用`@Component`,按使用`@Repository`/`@Service`等注解。 - 配置类与业务代码分离,便于管理。 ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值