Junit Test
@RunWith
--@RunWith就是一个运行器
--@RunWith(JUnit4.class)就是指用JUnit4来运行
--@RunWith(SpringJUnit4ClassRunner.class),让测试运行于Spring测试环 境,以便在测试开始的时候自动创建Spring的应用上下文
--@RunWith(Suite.class)的话就是一套测试集合
@ContextConfiguration
//整合JUnit4测试时,使用注解引入多个配置文件
//classpath: 加载当前maven工程的resources目录下的配置文件
//classpath*: 加载当前maven工程及其依赖工程的resources目录下的配置文
//applicationContext-*.xml: 读取所有符合规则的文件
@ContextConfiguration("classpath*:spring/applicationContext-*.xml")
//网上找的....
//单个文件
@ContextConfiguration(locations="../applicationContext.xml")
@ContextConfiguration(classes = SimpleConfiguration.class)
//多个文件
@ContextConfiguration(locations = { "classpath*:/spring1.xml", "classpath*:/spring2.xml" })
Spring
@Repository @Competent @Service @Controller
Spring bean声明
/**
* @Repository注解表示这个实现类是dao
* 如果后面不跟("personDaoImpl1")则默认将类名首字母小写当做这个实现类的id 即“personDaoImpl”
* 同理 @Service代表服务层 @Controller代表控制层
* @Competent代表组件 不确定属于什么的时候就用@Competent
*/
@Repository("personDaoImpl1")
public class PersonDaoImpl implements PersonDao {}
@Autowired @Qualifier
Spring bean自动注入
@Autowired
可以直接单独使用 前提是PersonDao接口只有一个实现类
若PersonDao接口有多个实现类 则需要跟上@Qualifier("实现类的id");
也可以使用@Value("#{实现类的id}")
或者@Resource(name="实现类的id")
/**
* @Autowired可以直接单独使用 前提是PersonDao接口只有一个实现类
* 若PersonDao接口有多个实现类 则需要跟上@Qualifier("实现类的id");
* 也可以使用 @Value("#{实现类的id}")
* 或者 @Resource(name="实现类的id")
*/
@Autowired
@Qualifier("iPersonService")//如果接口有多个实现类 则需要用@Qualifier()指定
IPersonService personService;
@Order
注意到
Validators
被注入了一个List<Validator>
,Spring会自动把所有类型为Validator
的Bean装配为一个List注入进来,这样一来,我们每新增一个Validator
类型,就自动被Spring装配到Validators
中了,非常方便。
因为Spring是通过扫描classpath获取到所有的Bean,而List是有序的,要指定List中Bean的顺序,可以加上@Order
注解
@Component
public class Validators {
@Autowired
List<Validator> validators;
public void validate(String email, String password, String name) {
for (var validator : this.validators) {
validator.validate(email, password, name);
}
}
}
-----------------------------------------------------------------------
//定义一个Validator的接口 并创建三个实现类 EmailValidator PasswordValidator NameValidator
public interface Validator {
void validate(String email, String password, String name);
}
-----------------------------------------------------------------------
@Component
@Order(1)
public class EmailValidator implements Validator {
public void validate(String email, String password, String name) {
if (!email.matches("^[a-z0-9]+\\@[a-z0-9]+\\.[a-z]{2,10}$")) {
throw new IllegalArgumentException("invalid email: " + email);
}
}
}
-----------------------------------------------------------------------
@Component
@Order(2)
public class PasswordValidator implements Validator {
public void validate(String email, String password, String name) {
if (!password.matches("^.{6,20}$")) {
throw new IllegalArgumentException("invalid password");
}
}
}
-----------------------------------------------------------------------
@Component
@Order(3)
public class NameValidator implements Validator {
public void validate(String email, String password, String name) {
if (name == null || name.isBlank() || name.length() > 20) {
throw new IllegalArgumentException("invalid name: " + name);
}
}
}
@Primary
在注入时,如果没有指出Bean的名字,Spring会注入标记有@Primary的Bean。这种方式也很常用。例如,对于主从两个数据源,通常将主数据源定义为@Primary
@Configuration
@ComponentScan
public class AppConfig {
@Bean
@Primary // 指定为主要Bean
@Qualifier("z")
ZoneId createZoneOfZ() {
return ZoneId.of("Z");
}
@Bean
@Qualifier("utc8")
ZoneId createZoneOfUTC8() {
return ZoneId.of("UTC+08:00");
}
}
@Resoure
@Resource
采用名称+类型的方式完成自动装配:
@Resource默认按bean的name进行查找,如果没有找到会按type进行查找,此时与@Autowired类似
(当采用名称进行装配的时候,在你用到这个实例的时候,所使用的名称一定要相同;如果是采用类型装配的话,它找的就是这个类。)
Resource 的作用相当于 @Autowired,只不过 @Autowired 按 byType 自动注入,而@Resource 默认按 byName 自动注入罢了。@Resource 有两个属性是比较重要的,分别是 name 和 type,Spring 将@Resource 注释的 name 属性解析为 Bean 的名字,而 type 属性则解析为 Bean 的类型。所以如果使用 name 属性,则使用 byName 的自动注入策略,而使用 type 属性时则使用 byType 自动注入策略。如果既不指定 name 也不指定 type 属性,这时将通过反射机制使用 byName 自动注入策略。
@Scope
对于Spring容器来说,当我们把一个Bean标记为
@Component
后,它就会自动为我们创建一个单例(Singleton),即容器初始化时创建Bean,容器关闭前销毁Bean。在容器运行期间,我们调用getBean(Class)获取到的Bean总是同一个实例。
还有一种Bean,我们每次调用getBean(Class),容器都返回一个新的实例,这种Bean称为Prototype(原型),它的生命周期显然和Singleton不同。声明一个Prototype的Bean时,需要添加一个额外的@Scope
注解
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) // @Scope("prototype")
public class MailSession {
...
}
@Configuration
AppConfig标注了
@Configuration
,表示它是一个配置类,因为我们创建ApplicationContext
时
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
使用的实现类是AnnotationConfigApplicationContext,必须传入一个标注了@Configuration
的类名
@Configuration
@ComponentScan
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);
User user = userService.login("bob@example.com", "password");
System.out.println(user.getName());
}
}
@ComponetScan
AppConfig还标注了
@ComponentScan
,它告诉容器,自动搜索当前类所在的包以及子包,把所有标注为@Component
的Bean自动创建出来,并根据@Autowired
进行装配
使用@ComponentScan
非常方便,但是,我们也要特别注意包的层次结构。通常来说,启动配置AppConfig位于自定义的顶层包(例如com.lyc),其他Bean按类别放入子包(com.lyc.bean)
@Configuration
@ComponentScan
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);
User user = userService.login("bob@example.com", "password");
System.out.println(user.getName());
}
}
@PropertySource(“app.properties”)
Spring容器还提供了一个简单的
@PropertySource
来自动读取配置文件。我们只需要在@Configuration
配置类上再添加一个注解
@Configuration
@ComponentScan
@PropertySource("app.properties") // 表示读取classpath的app.properties
public class AppConfig {
@Value("${app.zone:Z}")
String zoneId;
@Bean
ZoneId createZoneId() {
return ZoneId.of(zoneId);
}
}
SpringMVC
@ResponseBody
这个注解,就是当你引入了Jackson这个jar包的时候,再使用这个注解,SpringMVC就可以自动将它所修饰的方法的返回值转换为json格式,从而不需要人为的去转换
@RequestBody
允许request的参数在request体中,而不是在直接连接在地址后面。(放在参数前)
@RestController **
该注解为一个组合注解,相当于@Controller和@ResponseBody的组合,注解在类上,意味着,该Controller的所有方法都默认加上了@ResponseBody。
@RequestMapping
是一个用来处理请求地址映射的注解。可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
RequestMapping有六个属性:
value:指定请求的实际地址
method:指定请求的method类型,get、post、put、delete
consumes:指定处理请求的提交内容类型
produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回
params:指定request中必须包含某些参数值才让该方法处理
header:指定request中必须包含某些指定的header值,才让该方法处理请求