IOC的使用(2)
Spring超详细使用(1),内容包含各种方式获取组件、为不同类型的属性赋值、FactoryBean的使用等,传送地址:Spring IOC 超详细使用(1)
Spring AOP 的使用,传送地址:Spring AOP 的详细使用
文章目录
一、引用外部属性文件
使用C3P0数据库连接池(连接的是mysql8)
-
导包
-
在src目录下创建c3p0.properties文件,其中内容是:
jdbc.username=root
jdbc.password=root
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/book?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone = GMT
jdbc.driverClass=com.mysql.jdbc.Driver
//以上key是自定义的,并不是C3P0标准的key
注意:
(1) username是Spring中的一个关键字,为了防止配置文件中的key与其重名,可以为配置 文件的key加前缀
(2) 连接mysql8时,
i. 使用mysql - connector - java - 5.1.49.jar及以上版本
ii. url地址需要加后缀
- xml中编写
(1) 使用context名称空间加载外部配置文件
(2) xml中编写
<!-- location属性固定写法:classpath表示引用类路径下的资源-->
<context:property-placeholder location="classpath:c3p0.properties"/>
<!-- 创建一个数据库连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- ${key}动态取出配置文件中某个key对应的值 -->
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
</bean>
- 测试
@Test
public void test() throws SQLException {
ApplicationContext ioc = new ClassPathXmlApplicationContext("ioc.xml");
DataSource dataSource = (DataSource)ioc.getBean("dataSource");
System.out.println(dataSource.getConnection());
//com.mchange.v2.c3p0.impl.NewProxyConnection@64c87930
}
二、通过注解创建bean
Spring中有四个注解
(1) @Controller:推荐给控制层(Servlet)的组件加此注解
(2) @Service:推荐给业务逻辑层的组件添加此注解
(3) @Repository:推荐给数据库层(Dao层)的组件添加此注解
(4) @Component:推荐不属于以上的组件添加此注解
注意:
i. 给所要创建组件的类添加任何一个注解都可快速的将此组件添加到ioc容器的管理中
ii. 使用以上四个注解的任何一个均可,但尽量使用推荐
使用步骤:
(1) 导入aop包,以支持注解模式:
(2) 给所要创建组件的类添加以上注解
import org.springframework.stereotype.Service;
@Service
public class BookService {
//内容
}
(3) 让Spring自动扫描加了注解的组件,在xml文件中使用context名称空间
<!-- context:component-scan:自动扫描组件 -->
<!-- base-package:指定扫描的包,会将此包下的所有包的所有加了注解的类,自动的扫描进ioc容器中 -->
<context:component-scan base-package="com.qizegao"></context:component-scan>
<!-- com.qizegao.test 与 com.qizegao.util包都会被扫描,扫描之后符合条件的类图标会加小s -->
注意:
使用注解加入到容器中的组件,和使用配置文件加入到容器中的组件默认行为是一致的:
i. 组件的默认id是类名首字母小写
ii. 组件默认是单例的
(4) 测试
public void test() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("ioc.xml");
System.out.println(ioc.getBean("bookService") == ioc.getBean("bookService"));
//true
}
注意:
i. 可以修改组件的id
ii. 可以修改组件为多实例,如下:
@Service("newName") // 修改id为newName
@Scope(value="prototype") // 修改bean为多实例
public class BookService {
//内容
}
测试:
public void test() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("ioc.xml");
System.out.println(ioc.getBean("newName") == ioc.getBean("newName"));
//false
}
三、指定Spring扫描时不包含、只包含的组件
//不包含
<context:component-scan base-package="com.qizegao">
<!-- 使用context:exclude-filter指定扫描时不包含的组件:
1. type=annotation:按照注解进行排除,使用了expression中指定的注解(全类名)就不会被包含进来
2. type=assignable:按照指定的类进行排除,expression中指定要排除的全类名
-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
//只包含
//Spring默认是把包中所有满足条件的组件全部扫描进来,故应当先禁用默认的扫描规则
<!-- use-default-filters="false":禁用默认的扫描规则 -->
<context:component-scan base-package="com.qizegao" use-default-filters="false">
<!-- 使用context:include-filter指定扫描时只包含的组件:用法与context:exclude-filter一致 -->
<context:include-filter type="assignable" expression="com.qizegao.test.BookService"/>
</context:component-scan>
四、使用@Autowired注解根据类型实现自动装配
自动装配:自动的为某个属性赋值,一定是去容器中找这个属性对应的组件赋值,也就要求此组件 必须在容器中,否则报错
- 在com.qizegao.test包下创建两个类
@Repository
public class BookDao {
public void saveBook() {
System.out.println("正在使用BookDao保存图书");
}
}
@Service
public class BookService {
@Autowired
//使用此注解自动的为其赋值,无需再new
private BookDao bookDao;
public void save() {
System.out.println("调用BookDao保存图书");
bookDao.saveBook();
}
}
- xml中让Spring扫描加了注解的组件
<context:component-scan base-package="com.qizegao"></context:component-scan>
- 测试
public void test() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("ioc.xml");
//BookService默认是单例的,使用class获取
BookService bookService = ioc.getBean(BookService.class);
bookService.save();
/**
* 调用BookDao保存图书
* 正在使用BookDao保存图书
*/
}
五、@Autowired注解自动装配原理
@Autowired
private BookDao bookDao;
先按照类型(BookDao)去容器中找对应的组件:getBean(BookDao.class):
(1) 找到一个,赋值
(2) 没有找到,抛异常
(3) 找到多个(会将此类的子类也找到):
将变量名(bookDao)作为id继续去容器中找对应的组件:
i. 匹配成功,装配
ii. 匹配失败,报错
注意:
(1)
@Autowired
@Qualifier(“xxx”) //使用此注解可以使用xxx作为id去匹配,而不是使用变量名作为id
private BookDao bookDao;
(2) 匹配到则装配,匹配不到则赋null值:@Autowired(required=false)
六、在方法上使用@Autowired
- 这个方法会在bean创建的时候自动运行
- 这个方法的每个参数都会按照上述自动注入值
(1) BookService中的方法
//BookService与BookDao均已注册到ioc容器中
@Service
public class BookService {
@Autowired(required=false)
//参数的位置也可以使用@Qualifier注解
public void method(@Qualifier("bookDao")BookDao bookDao) {
System.out.println(bookDao);
}
}
(2) 测试
@Test
public void test() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("ioc.xml");
//运行后输出:com.qizegao.test.BookDao@2bbaf4f0
}
七、@Autowired与 @Resource的区别
二者可以互换
@Autowired:功能最强大,是Spring定义的注解,但只支持Spring框架
@Resource:扩展性强,是Java定义的标准,如果切换成另外的容器(非Spring)也可使用
八、泛型依赖注入
注册一个组件时,它的泛型也是参考标准,如下图:
注意:注册有继承关系的组件时,只需要在子类上加注解,父类不用加会自动注入
九、Spring的单元测试
(1) 导包:
(2) 在测试类之上使用两个注解:
① @ContextConfiguration(locations=“classpath:ioc.xml”)
指定Spring配置文件的位置
② @RunWith(SpringJUnit4ClassRunner.class)
指定用哪种驱动进行单元测试,默认是Junit
(3) 好处:无需使用getBean方法获取组件,直接在要获取的组件上加注解@Autowired,Spring 会自动装配
(4) 使用案例:
@ContextConfiguration(locations="classpath:ioc.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class test {
@Autowired
BookDao bookDao;
@Test
public void test() {
System.out.println(bookDao);
//com.qizegao.test.BookDao@62e136d3
}
}