基于注解的 IOC 配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mingqi</groupId> <artifactId>springAnnoioc</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>commons-dbutils</groupId> <artifactId>commons-dbutils</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>sqljdbc4</artifactId> <version>4.0</version> </dependency> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> </dependency> </dependencies> </project>
2、使用@Component 注解配置管理的资源
/** * 账户的业务层实现类 */ @Component("accountService") public class AccountServiceImpl implements IAccountService { private IAccountDao accountDao; public void setAccountDao(IAccountDao accountDao) { this.accountDao = accountDao; } } /** * 账户的持久层实现类 */ @Component("accountDao") public class AccountDaoImpl implements IAccountDao { private DBAssit dbAssit; }
<?xml version="1.0" encoding="UTF-8"?> <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"> <!-- 告知spring在创建容器时要扫描的包 --> <context:component-scan base-package="com.mingqi"></context:component-scan> <!--配置QueryRunner--> <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype"> <!--注入数据源--> <constructor-arg name="ds" ref="dataSource"></constructor-arg> </bean> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/> <property name="jdbcUrl" value="jdbc:sqlserver://localhost:1433;DatabaseName=test"/> <property name="user" value="sa"/> <property name="password" value="123sa"/> </bean> <bean id="usersDao" class="com.mingqi.dao.impl.UsersDaoimpl"> <property name="runner" ref="runner"></property> </bean> <bean id="usersService" class="com.mingqi.service.impl.UsersServiceImpl"> <property name="usersDao" ref="usersDao"></property> </bean> </beans>
4、常用注解
(1)用于创建对象的 相当于:<bean id="" class="">
① @Component
作用:把资源让 spring 来管理。相当于在 xml 中配置一个 bean。
属性:value:指定 bean 的 id。如果不指定 value 属性,默认 bean 的 id 是当前类的类名。首字母小写。
② @Controller @Service @Repository 他们三个注解都是针对一个的衍生注解,他们的作用及属性都是一模一样的。他们只不过是提供了更加明确的语义化。
基于注解的 spring IoC 配置中,bean 对象的特点和基于 XML 配置是一模一样的,但是还是需要spring的xml配置文件,name能不能不写这个bean.xml,所有的配置都用注解来实现呢?
(6)新注解说明
①@Configuration 作用:用于指定当前类是一个 spring 配置类,当创建容器时会从该类上加载注解。获取容器时需要使用AnnotationApplicationContext(有@Configuration 注解的类.class)。
/* spring 的配置类,相当于 bean.xml 文件 */ @Configuration public class SpringConfig { }
③@Bean 作用:该注解只能写在方法上,表明使用此方法创建一个对象,并放入spring容器中
属性:name:给当前@Bean注解方法创建的对象指定一个名称(即bean的id)
/* spring 的配置类,相当于 bean.xml 文件 */ @Configuration @ComponentScan("com.mingqi") public class SpringConfig { private DataSource dataSource; private QueryRunner runner; /** * 注入dataSource * @return */ @Bean(name="dataSource") public ComboPooledDataSource createDataSource() { try { ComboPooledDataSource ds = new ComboPooledDataSource(); ds.setUser("sa"); ds.setPassword("123sa"); ds.setDriverClass("com.microsoft.sqlserver.jdbc.SQLServerDriver"); ds.setJdbcUrl("jdbc:sqlserver://localhost:1433;DatabaseName=test"); return ds; } catch (Exception e) { throw new RuntimeException(e); } } /** * 创建一个QueryRunner 并放入bean容器中 * @param dataSource * @return */ @Bean(name="runner") public QueryRunner runner(DataSource dataSource) { //this.dataSource = dataSource; return new QueryRunner(dataSource); } }
public class JdbcConfig { @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") public DataSource createDataSource() { try { ComboPooledDataSource ds = new ComboPooledDataSource(); ds.setDriverClass(driver); ds.setJdbcUrl(url); ds.setUser(username); ds.setPassword(password); return ds; } catch (Exception e) { throw new RuntimeException(e); } } }
properties 文件内容:
jdbc.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
jdbc.url=jdbc:sqlserver://localhost:1433;DatabaseName=test
jdbc.username=sa
jdbc.password=123sa
@Configuration @PropertySource("classpath:com/mingqi/config/jdbc.properties") public class JdbcConfig { } @Configuration @ComponentScan("com.mingqi") @Import({ JdbcConfig.class}) public class SpringConfig { }
(6) 通过注解获取容器:
(7) 在测试类中,每个测试方法都有以下两行代码:
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
IAccountService as = ac.getBean("accountService",IAccountService.class);
针对上述问题,我们需要的是程序能自动帮我们创建容器。一旦程序能自动为我们创建 spring 容器,我们就无须手动创建了,问题也就解决了。
@RunWith(SpringJUnit4ClassRunner.class) public class AccountServiceTest { } @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations= {"classpath:bean.xml"}) public class AccountServiceTest { } /* @ContextConfiguration 注解: locations 属性:用于指定配置文件的位置。如果是类路径下,需要用 classpath:表明 classes 属性:用于指定注解的类。当不使用 xml 配置时,需要用此属性指定注解类的位置。 */
③ 使用@Autowired 给测试类中的变量注入数据
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations= {"classpath:bean.xml"}) public class AccountServiceTest { @Autowired private IAccountService as ; }