Spring:05 IoC-基于注解配置的Spring开发

Spring注解开发

Spring有两种配置方式:xml配置、注解配置。

​ 注解配置的目的,是为了简化XML配置。

Spring的注解有2种:原始注解、新注解。

1.原始注解

针对于自定义的类,能够进入到类实现代码中去添加“注解”,以注解代替xml配置文件中的标签配置。

注解说明
@Component使用在java类上,用于实例化Bean
@Controller使用在web层类上,用于实例化Bean
@Service使用在service层类上,用于实例化Bean
@Repository使用在dao层类上,用于实例化Bean
@Autowired使用在java类的属性字段上,用于根据类型注入依赖
@Qualifier结合@Autowired一起使用,用于根据名称进行依赖注入
@Resource相当于@Autowired+@Qualifier,按照名称进行依赖注入
@Value普通属性注入值
@Scope标注Bean的作用范围
@PostConstruct使用在方法上,标注该方法是Bean的初始化方法
@PreDestroy使用在方法上,标注该方法是Bean的销毁方法

对比着Spring中XML配置开发来理解。

1.1 XML配置内容

<!--配置Dao层的Bean对象-->
    <bean id="userDaoImpl" class="cn.leap.dao.impl.UserDaoImpl">
        <property name="username" value="John"/>
    </bean>

    <!--配置Service层的Bean对象-->
    <bean id="userServiceImpl" class="cn.leap.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDaoImpl"/>
    </bean>

现在要通过”注解“来替换上面的两个标签。

1.2 dao层注解配置

//@Component("userDaoImpl")
@Repository("userDaoImpl") //@Repository 用于dao层实例化Bean
public class UserDaoImpl implements UserDao {

    @Value("John")
    private String username;

    @Value("${jdbc.driver}")//使用SpEL表达式获取外部配置文件的数据
    private String driver;

    @Override
    public void save() {
        System.out.println("UserDaoImpl: save()............");
        System.out.println(username);
        System.out.println(driver);
    }
}

外部配置文件 jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db1
jdbc.username=root
jdbc.password=root

1.3 service层的注解配置

//@Component("userService")
@Service("userServiceImpl") //@Service 用于service层实例化Bean
public class UserServiceImpl implements UserService {

    /*@Autowired
    @Qualifier("userDaoImpl")*/
    @Resource(name="userDaoImpl")
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void save() {
        userDao.save();
    }
}

1.4 XML中配置”组件扫描“功能

在Spring主配置文件applicationContext.xml中进行配置。

这是指定哪个包及其子包下的Bean,告诉Spring,它们需要进行扫描以便识别使用注解配置的类、字段和方法等信息。

<context:component-scan base-package="cn.leap"/>

如果不给Spring配置这个”组件扫描“功能,那么运行测试代码时,会报如下错误

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'userServiceImpl' available

显示没有定义相应的Bean类。其实不是没有定义,而是Spring没找到。

为什么没找到?

​ 原因:”注解“在Java类进行了配置,但还未告诉Spring。

这里的context,是一个命名空间,需要在Spring配置文件中,对它进行配置。

context命名空间的配置

Spring配置文件根标签标签中,初始内容如下

<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">
</beans>

配置context命名空间后,如下:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       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
                            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
</beans>

1.5 测试代码

public class SpringAnnotationTest {
    /**
     * 原始注解测试
     */
    @Test
    public void testSpringOriginAnnotation() {
        String config = "applicationContext.xml";
        ApplicationContext context = new ClassPathXmlApplicationContext(config);
        UserService service = (UserService) context.getBean("userServiceImpl");
        service.save();
    }
}

1.6 运行结果

没有配置组件扫描时,报错:

​ org.springframework.bean.factory.NoSuchBeanDefinitionException: No bean named ‘userServiceImpl’ available

[外链图片转存失败(img-kVuExVOs-1569086800475)(C:\Users\ASUS\AppData\Local\Temp\1562435360199.png)]

配置组件扫描后,运行正常。

userDaoImpl: save()............
John
com.mysql.jdbc.Driver

1.7 分析总结

注解配置是简化了XML配置,但会发现,并没有完全取代XML配置,如**”组件扫描“**标签就仍然是在XML文件中进行配置的。而且,原始注解也取代不了此标签。

对于那些无法用XML进行配置的内容,Spring团队后来提供了一套”Spring新注解“规则,来实现***Spring的全注解开发***。

但实际应用中,通常都是”XML配置+注解配置“的方式。

2. 新注解

针对原始注解没办法进行注解的xml标签

使用了新注解后,Spring就可以实现”全注解开发“,即XML配置文件可以不再需要了。

注解说明
@Configuration用于类上,指定当前类是一个 Spring 配置类,当创建容器时会从该类上加载注解
@ComponentScan用于指定 Spring 在初始化容器时要扫描的包。 作用和在 Spring 的 xml 配置文件中的 <context:component-scan base-package=“com.yeats”/>一样
@Bean使用在方法上,标注将该方法的返回值存储到 Spring 容器中
@PropertySource用于加载.properties 文件中的配置
@Import用于导入其他配置类

(1)非自定义类的标签

​ 外部的依赖包,源码进去了,也修改不了,所有没法在上面添加“注解”。

(当然也不是完全不行,如果修改源码后,重新导入就可以了,但那实在太麻烦了,一般没人那样做)

​ 如:C3P0数据库连接池的实现类 ComboPooledDataSource,它下面这段XML配置,就无法用Spring原始注 解进行配置。

 <bean id="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
 </bean>

(2)标签

<import sources="spring-config-dataSource"/>

(3)加载properties配置文件的标签

<context:property-placeholder location="classpath:jdbc.properties"/>

(4)组件扫描标签

<context:component-scan base-package="cn.leap"/>

2.1 创建Spring核心配置类 @Configuration

通常都命名为 SpringConfiguration.java 它相当于取代了applicationContext.xml

创建类文件后,需要通过注解声明它是Spring核心配置类。

@Configuration//声明该类为Spring核心配置类
public class SpringConfiguration {
    
}

2.2 @ComponentScan: 取代”组件扫描“标签

<context:component-scan base-package=“cn.leap”/>

@Configuration//声明该类为Spring核心配置类
@ComponentScan("cn.leap")//取代组件扫描标签
public class SpringConfiguration {

}

2.3 @PropertySource: 取代加载properties配置文件的标签

<context:property-placeholder location="classpath:jdbc.properties"/>

外部配置文件 jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db1
jdbc.username=root
jdbc.password=root

Spring中的配置文件,通常会根据不同的功能类别,单独建配置文件。

这里,可以新建一个数据源配置类:DataSourceConfiguration.java

@PropertySource("classpath:jdbc.properties")//加载配置文件
public class DataSourceConfiguration {

    /**
     * SpEL表达式获取键值
     */
    @Value("${jdbc.driver}")
    private String driver;

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;
}

注意:

这只是加载了配置文件,还并没有用它。一个完整的DataSourceConfiguration配置类,应该对外提供一个方法,用于传递DataSource对象

2.4 @Import: 取代标签

<import sources="spring-config-dataSource"/>

主配置类中,导入其他配置类。

@Configuration//声明该类为Spring核心配置类
@ComponentScan("cn.leap")//指定进行组件扫描的包
@Import({DataSourceConfiguration.class})//导入其他配置类
public class SpringConfiguration {

}

2.5 @Bean: 取代非定义类的标签

@Bean  使用在方法上,标注将该方法的返回值存储到Spring容器中

非定义类,原先在XML中的配置如下:

 <bean id="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
 </bean>

使用在**“方法”**上,那该方法写什么?在哪儿写?

​ 它属于哪块功能,就写到对应的配置类中去。

这个ComboPooledDatasource类是跟数据源相关的,所以把它写到DataSourceConfiguration.java中去

@PropertySource("classpath:jdbc.properties")//加载配置文件
public class DataSourceConfiguration {

    /**
     * SpEL表达式获取键值
     */
    @Value("${jdbc.driver}")
    private String driver;

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    @Bean(name = "dataSource")//指示Spring将当前方法的返回值以指定名称放到Spring容器中
    public DataSource getDataSource() throws Exception {
        //获取连接池对象
        ComboPooledDataSource ds = new ComboPooledDataSource();
        ds.setDriverClass(driver);
        ds.setJdbcUrl(url);
        ds.setUser(username);
        ds.setPassword(password);
        //返回DataSource对象
        return ds;
    }
}

2.6 测试代码

测试什么?加载核心配置类创建Spring容器

public class SpringAnnotationTest {

    /**
     * Spring新注解的测试
     */
    @Test
    public void testSpringNewAnnotation() throws Exception {
        //创建 Spring容器,并从容器中获取数据源
        ApplicationContext context = new 			AnnotationConfigApplicationContext(SpringConfiguration.class);//必须指明主配置类的字节码文件
        DataSource dataSource = (DataSource) context.getBean("dataSource");

        //从数据源中获取连接
        Connection connection = dataSource.getConnection();
        System.out.println(connection);

        //dao、service的测试
        UserService userService = (UserService) context.getBean("userServiceImpl");
        userService.save();
    }

    /**
     * Spring原始注解测试
     */
    @Test
    public void testSpringOriginAnnotation() {
        String config = "applicationContext.xml";
        ApplicationContext context = new ClassPathXmlApplicationContext(config);
        UserService service = (UserService) context.getBean("userServiceImpl");
        service.save();
    }
}

2.7 分析总结

使用新注解后,再配合上原始注解,就实现了Spring的全注解开发,不用写XML配置。

需要注意两点:

1. 实际开发中,其实是XML配置+注解配置,两者并用,相辅相成的。
	2. 所谓的”原始注解“,是指Spring稍早时候提供的注解。使用新注解,也一定会配合原始注解,两者一块使用,才能完成所谓的”Spring全注解开发“。

plicationContext.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(config);
UserService service = (UserService) context.getBean(“userServiceImpl”);
service.save();
}
}


### 2.7 分析总结

使用**新注解**后,再配合上**原始注解**,就实现了Spring的**全注解开发**,不用写XML配置。

需要注意两点:

 	1. 实际开发中,其实是XML配置+注解配置,两者并用,相辅相成的。
		2. 所谓的”原始注解“,是指Spring稍早时候提供的注解。使用新注解,也一定会配合原始注解,两者一块使用,才能完成所谓的”Spring全注解开发“。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值