本文基于下述教程编写:【B站】ssm教程
注解XML交叉运用
@Component
他们三个注解都是针对一个的衍生注解,他们的作用及属性都是一模一样的。 他们只不过是提供了更加明确的语义化。
@Controller
:一般用于表现层的注解。
@Service
:一般用于业务层的注解。
@Repository
:一般用于持久层的注解。
@Autowired
作用:
自动按照类型注入。当使用注解注入属性时,set
方法可以省略。它只能注入其他 bean
类型(非基本类型及String
)。当有多个类型匹配时,使用要注入的对象变量名称作为 bean
的 id
,在 spring
容器查找,找到了也可以注入成功。找不到就报错。
@Component
public class AccountServiceImpl implements IAccountService {
//自动注入
@Autowired
private IAccountDao accountDao1;
}
上图需要注入的成员变量名称是accountDao
,虽然有两个实现类Bean
与之对应,但是进行第二步查找时名称不对应,会查找失败。
@Qualifier
:在自动按照类型注入的基础之上,再按照 Bean 的 id 注入。它在给字段注入时不能独立使用,必须和 @Autowire 一起使用;但是给方法参数注入时,可以独立使用。
@Component
public class AccountServiceImpl implements IAccountService {
@Autowired
@Qualifier("accountDao1")//名称不一,但可以指定对应的bean
private IAccountDao accountDao;
@Resource
直接按照 Bean 的 id
注入。它也只能注入其他 bean
类型。
无论是@Autowired
还是@Resource
都无法实现基本数据类型
、String
的数据注入,并且集合这样复杂的数据类型只能通过XML配置注入,注解方式无能为力。
@PostConstruct
用于指定Bean
初始化方法
@PreDestroy
用于指定Bean
销毁方法,注意多例模式只能被java
回收,不能主动销毁。
在注解方式实现容器下,bean.xml
要用有别于XML
实现的约束:
<?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管理-->
<!--扫描需要反射的Bean的目录-->
<context:component-scan base-package="com.spring5Annotation"> </context:component-scan>
</beans>
但是有一个问题,这并没有和XML
方式配置有根本上的差别,还是基于bean.xml
存在。经过写配置类彻底变成纯注解配置。
纯注解
@Configuration
@ComponentScan("com.littleinstance")//扫描包下的字节码文件,不然提示找不到Bean
public class SpringConfiguration {
@Bean(name = "runner")//默认单例
@Scope("prototype")
public QueryRunner createQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
@Bean(name = "dataSource")
public DataSource createDataSource() {
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setUser("root");
ds.setPassword("root");
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql://localhost:3306/ssmTest");
return ds;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
DateSource
是QueryRunner
的成员属性,QueryRunner
是AccountDao
的成员属性,AccountDao
是AccountService
的成员属性。通过xml配置是分别配置不同的<bean>
标签,用<property>
标签的ref
属性指定实现依赖的。
而在配置类中需要写创造Bean
的方法并用@Bean
标记从而放进Spring
容器里面的,只要放进了容器,会自动寻找合适的对象自动完成匹配。注意QueryRunner
要指定为多例模式,否则危及线程安全。此时bean.xml
不再需要,但是要再测试类完成文件引用的修改:
//基于XML配置
//ac=new ClassPathXmlApplicationContext("bean1.xml");
//基于注解配置
ac=new AnnotationConfigApplicationContext(SpringConfiguration.class);
但是,Spring
如何匹配DataSource
对象到QueryRunner
里面的呢?万一QueryRunner
有两个DataSource
呢?怎么完成一一对应?
是的,当有多个同类型的对象就回到一开始讨论的情况,匹配对应的方法也是和XML
配置方法一样的,此时@Qualifier
注解就可以在参数的旁边标注具体使用哪个Bean
作为QueryRunner
的参数。另外,将参数名改成Bean
的ID
,不使用@Qualifier
也可以实现,不过就不符合命名的自由规范了。
@ComponentScan
扫描包下的字节码文件,不然提示找不到Bean,相当:
<!--扫描需要反射的Bean的目录-->
<context:component-scan base-package="com.spring5Annotation"> </context:component-scan>
细节:当如上方式加载目标类字节码文件时,@Configuration
可以省略,但是当需要用到的配置类不当字节码文件传入时,一定要被指定扫描并且标记@Configuration
,否则找不到Bean
。
然而人懒起来真的可怕,当你不想标注@Configuration
,也不想引入字节码文件时,还希望多个配置文件可以有个明确的父子关系,下面这个标签应运而生。
@Import
用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration
注解。当然,写上也没问题。 尽管如此,@ComponentScan
还是不能省略。
@PropertySource
用于加载.properties
文件中的配置,参数value[]
:用于指定 properties
文件位置,可传入多个或单个路径,单个可以省略"value="
和大括号
。如果是在类路径下,需要写上 classpath:
。
整合junit测试
为什么Spring要整合junit?
我们追求各个框架能够充分合作,并且能写少一行代码绝对不想写多一行。
Spring要整合junit,怎么理解
当我们不整合时,每次测试类代码中就会获取资源文件手动创建一次Spring容器:
但是,Junit
并不能预测到我们用啥子框架,他并不知道Spring
的存在,所以进行整合就要换掉Junit
原始运行器。好在Junit
也不小家子脾气,大度地为我们提供了注解@RunWith
让我们根据需求自己手动换成自己所需的运行器。Spring
当然也不小气,为了方便我们整合测试类,提供了一个叫SpringJUnit4ClassRunner
的类,该类只需要你提供创建Spring
容器的配置文件/配置类
,就可以自动为我们创建容器,一行代码都不用写。
Spring整合junit步骤
1.拿到Spring专门为我们提供的整合测试类运行器:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
当然Junit也少不了,但是要明确版本要求大于等于4.12
(Spring5.0以上要求),不然报错:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
2.告诉Junit
我们嫌弃你了,换成Spring
的运行器:
@RunWith(SpringJUnit4ClassRunner.class)
3.告知Spring你在用什么配置容器,XML方式就给出bean.xml文件,注解方式就给出配置类字节码文件。
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration( classes = SpringConfiguration.class) //注解方式用classes
@ContextConfiguration( locations = "classpath:bean.xml") //xml方式用location,别忘了classpath:
4.依赖注入,配置成员变量。来到这里,IAccountService
被自动依赖注入,其实在Spring
容器里IAccount
的匹配过程也如文首提到的流程走了一遍。在整合测试类中少写了读取配置的代码,不用ApplicationContext
的getBean()
方法得到实例对象。
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration( classes = SpringConfiguration.class)
@ContextConfiguration( locations = "classpath:bean.xml")
public class AccountServiceTest {
@Autowired
IAccountService as;