SpringBoot常用注解速查

@Component、@Responsity、@Service、@Controller

作用在类上,表明这些类是交给spring容器进行管理的。

@Controller

控制器,类中注入服务

@RestController
public class DamsController {

    @Autowired
    MetaDataService metaDataService;

    @PostMapping("createMeta")
    public SimpleResp metaDataScan(String id,String cipherKey) {
        try {
            metaDataService.scan(id, cipherKey);
            return new SimpleResp(true);
        } catch (Exception e) {
            log.error("metaDataScan fail", e);
            return new SimpleResp(false, e.getMessage());
        }
    }
}

@Service

服务,默认名称是类名(头字母小写),可以@Service(“xxxx”)这样来指定,类中注入DAO

@Service
public class MetaDataService {

    @Autowired
    MetaDataDao metaDataDao;

    public void scan(String id, String cipherKey) throws Exception {
        List<DataDbms> dataDbmsList = metaDataDao.getDataDbmsList(id);
     //...
    }
}

上述代码让Spring创建一个名字叫metaDataService的实例

@Responsity

DAO,实现DAO访问

@Repository
public class MetaDataDao {

    @Autowired
    JdbcTemplate jdbcTemplate;

    public List<DataDbms> getDataDbmsList(String id) {
        String sql = "SELECT * FROM test";
        if (id != null && !id.isEmpty()) sql += (" where id=" + id);
        return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(DataDbms.class));
    }

上述代码让Spring创建一个名字叫metaDataDao的实例

@Component

把普通ORM实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>

@RestController与@Controller区别

官方文档:@RestController is a stereotype annotation that combines @ResponseBody and @Controller.

意思是:@RestController注解相当于@ResponseBody + @Controller合在一起的作用。web开发用Controller,REST项目用RestController

  • 使用@Controller注解,在对应的方法上,视图解析器可以解析return的jsp,html页面,并且跳转到相应页面。若返回json等内容到页面,则需要加@ResponseBody注解
@CrossOrigin
@Controller
public class FileUploadController {

//跳转到上传文件的页面
@RequestMapping(value="/gouploadimg", method = RequestMethod.GET)
public String goUploadImg() {
//跳转到 templates 目录下的 uploadimg.html
return "uploadimg";
}

//处理文件上传
@RequestMapping(value="/testuploadimg", method = RequestMethod.POST)
public @ResponseBody String uploadImg(@RequestParam("file") MultipartFile file,
HttpServletRequest request) {
System.out.println("调用文件上传方法");
String contentType = file.getContentType();
String fileName = file.getOriginalFilename();
  • @RestController注解,返回json数据不需要在方法前面加@ResponseBody注解了,但使用@RestController这个注解,就不能返回jsp,html页面,视图解析器InternalResourceViewResolver无法解析jsp,html页面,直接返回的内容就是Return里的内容
@CrossOrigin
@RestController
public class HospitalController {
    //注入Service服务对象
    @Autowired
    private HospitalService hospitalService;

    /**
     * 查询所有医院信息(未分页)
     */
    @RequestMapping(value = "findAllHospital",method = RequestMethod.GET)
    public  List<Hospital> findAllHospital(){
        List<Hospital> hospitalList= hospitalService.findAllHospital();
        return hospitalList;
    }

@Configuration和@Component区别

一句话概括就是@Configuration中所有带@Bean注解的方法都会被动态代理,因此调用该方法返回的都是同一个实例。

@Configuration定义:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
    String value() default "";
}

从定义来看, @Configuration 注解本质上还是 @Component,因此 <context:component-scan/>或者 @ComponentScan 都能处理@Configuration 注解的类

@Configuration 标记的类必须符合下面的要求:

  • 配置类必须以类的形式提供(不能是工厂方法返回的实例),允许通过生成子类在运行时增强(cglib 动态代理)。
  • 配置类不能是 final 类(没法动态代理)。
  • 配置注解通常为了通过 @Bean 注解生成 Spring 容器管理的类,
  • 配置类必须是非本地的(即不能在方法中声明,不能是 private)。
  • 任何嵌套配置类都必须声明为static。
  • @Bean 方法可能不会反过来创建进一步的配置类(也就是返回的 bean 如果带有 @Configuration,也不会被特殊处理,只会作为普通的 bean)。

加载过程

Spring 容器在启动时,会加载默认的一些PostProcessor,其中就有 ConfigurationClassPostProcessor,这个后置处理程序专门处理带有 @Configuration 注解的类,这个程序会在 bean 定义加载完成后,在 bean 初始化前进行处理。主要处理的过程就是使用 cglib 动态代理增强类,而且是对其中带有 @Bean 注解的方法进行处理。

@Bean

@Configuration
public class MyBeanConfig {

    @Bean
    public Country country(){
        return new Country();
    }

    @Bean
    public UserInfo userInfo(){
        return new UserInfo(country());
    }

}

上例中直接调用 country() 方法返回的是同一个实例,实际调用的是spring中cglib的代理(源码略)

@Component 注解并没有通过 cglib 来代理@Bean 方法的调用,因此像下面这样配置时,就是两个不同的 country,如下:

@Component
public class MyBeanConfig {

    @Bean
    public Country country(){
        return new Country();
    }

    @Bean
    public UserInfo userInfo(){
        return new UserInfo(country());
    }

}

有些特殊情况下,我们不希望 MyBeanConfig 被代理(代理后会变成WebMvcConfig$$EnhancerBySpringCGLIB$$8bef3235293)时,就得用 @Component,这种情况下,上面的写法就需要改成下面这样:

@Component
public class MyBeanConfig {

    @Autowired
    private Country country;

    @Bean
    public Country country(){
        return new Country();
    }

    @Bean
    public UserInfo userInfo(){
        return new UserInfo(country);
    }

}

这种方式可以保证使用的同一个 Country 实例,在 @Configuration 注解定义的 bean 方法中可以直接调用方法,不需要 @Autowired 注入后使用。

@Resource、@Autowired

用来修饰字段、构造函数或者设置方法,spring容器会自动的将我需要的属性、方法或对象提供出来。有时候可以替换使用,有时则不可以。

  • 可互换

@Resource和@Autowired都可以作为注入属性的修饰,在接口仅有单一实现类时,两个注解的修饰效果相同,可以互相替换,不影响使用。

  • 不能互换

@Resource是Java自己的注解,@Resource有两个属性是比较重要的,分是name和type;Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。

@Autowired是spring的注解,是spring2.5版本引入的,Autowired只根据type进行注入,不会去匹配name。如果涉及到type无法辨别注入对象时,那需要依赖@Qualifier或@Primary注解一起来修饰。

public interface Human {
  String runMarathon();
}

@Service
public class Man implements Human {

  public String runMarathon() {
    return "A man run marathon";
  }
}

@Service
public class Woman implements Human {

  public String runMarathon() {
    return "An woman run marathon";
  }
}

@RestController
@RequestMapping("/an")
public class HumanController {

  @Resource
  private Human human;

  @RequestMapping("/run")
  public String runMarathon() {
    return human.runMarathon();
  }
}

HumanController里的Human直接使用@Resource报错expected single matching bean but found 2: man,woman,@Autowired报错required a single bean, but 2 were found:- man: defined in file [...] - woman: defined in file [...],正确写法:

  @Resource(name="woman")
  private Human human;
//或:
  @Resource
  @Qualifier("woman")
  private Human human;
//或:
  @Autowired
  @Qualifier("woman")
  private Human human;
//或:
//@Primary是修饰实现类的告诉spring,如果有多个实现类时,优先注入被其注解修饰的那个。
@Service
@Primary
public class Man implements Human {

  public String runMarathon() {
    return "A man run marathon";
  }
}

上文中注入了一个字段@Resource private Human human; 这个表示字段名为human,也就是表示需要注入名字是human的bean,但是并没有名字为human的bean,这时就会走byType注入, 所以说这个注入成功是根据byType注入成功的,而不是byName。

@RequestMapping

一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

@RequestParam

@RequestParam(value=”参数名”, required=true/false, defaultValue=””)

  • value:请求参数名(必须配置)单一参数时,可简化如下:
 @GetMapping("edit1")
    public String edit1(@RequestParam("userId") Integer userId, Model model) {

  • required:是否必需,默认为true,即请求中必须包含该参数,如果没有包含,将会抛出异常

  • defaultValue:默认值,如果设置了该值,required将自动设为false(无论你是否配置了required,配置了什么值,都是false),如果没有传该参数,就使用默认值

  • 接收传递过来的数组:

 @PostMapping("delete")
    @ResponseBody
    public RestResponse delete(@RequestParam(value = "ids[]", required = false) List<Long> ids) {
        if (null == ids) {
            return RestResponse.failure("ID不能为空" );
        }
        for (Long id : ids) {
            rongheMobileListService.deleteById(id);
        }
        return RestResponse.success();
    }

  • 接收传递过来的Map<String, Object>:
@PostMapping("entry")
    @ResponseBody
    public RestResponse add(
@RequestParam(value = "data[mobile]") String mobile,
@RequestParam(value = "data[pro]") String pro,
@RequestParam(value = "data[realTime]", required = false) String realTime,
@RequestParam(value = "data[sjmc]", required = false) String sjmc,
@RequestParam(value = "data[mobBm]", required = false) String mobBm,
@RequestParam(value = "data[mobMc]", required = false) String mobMc,
@RequestParam(value = "data[orderId]", required = false) String orderId,
@RequestParam(value = "data[sn]") String sn,
@RequestParam(value = "data[bakMobile]", required = false) String bakMobile) {
        return RestResponse.success();
    }

@Conditional

Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean。定义如下:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME) 
@Documented
public @interface Conditional {
    Class<? extends Condition>[] value();
}
//传入一个Class数组(多种条件类,与的关系),需要继承Condition接口
public interface Condition {
    boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
}

例子:

public class Person {

    private String name;
    private Integer age;
// Getter Setter
    @Override
    public String toString() {
        return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
}
/**
*   BeanConfig类,用于配置两个Person实例并注入
**/
@Configuration
public class BeanConfig {

    @Bean(name = "bill")
    public Person person1(){
        return new Person("Bill Gates",62);
    }

    @Bean("linus")
    public Person person2(){
        return new Person("Linus",48);
    }
}
/**
*   行验证这两个Bean是否注入成功
**/
public class ConditionalTest {

    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);

    @Test
    public void test1(){
      String osName = applicationContext.getEnvironment().getProperty("os.name");
        System.out.println("当前系统为:" + osName);
        Map<String, Person> map = applicationContext.getBeansOfType(Person.class);
        System.out.println(map);
    }
}

根据当前操作系统来注入Person实例,windows下注入bill,linux下注入linus

  • 首选实现Condition接口:
public class WindowsCondition implements Condition {

    /**
     * @param conditionContext:判断条件能使用的上下文环境
     * @param annotatedTypeMetadata:注解所在位置的注释信息
     * */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        //获取ioc使用的beanFactory
        ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
        //获取类加载器
        ClassLoader classLoader = conditionContext.getClassLoader();
        //获取当前环境信息
        Environment environment = conditionContext.getEnvironment();
        //获取bean定义的注册类
        BeanDefinitionRegistry registry = conditionContext.getRegistry();

        //获得当前系统名
        String property = environment.getProperty("os.name");
        //包含Windows则说明是windows系统,返回true
        if (property.contains("Windows")){
            return true;
        }
        return false;
    }
}
//conditionContext提供了多种方法,方便获取各种信息,是SpringBoot中@ConditonalOnXX注解多样扩展的基础

public class LinuxCondition implements Condition {

    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {

        Environment environment = conditionContext.getEnvironment();

        String property = environment.getProperty("os.name");
        if (property.contains("Linux")){
            return true;
        }
        return false;
    }
}

接着就是使用这两个类了,因为此注解可以标注在方法上和类上,所以分开测试:

  • 标注在方法上,一个方法只能注入一个bean实例,所以@Conditional标注在方法上只能控制一个bean实例是否注入

@Configuration
public class BeanConfig {

    //只有一个类时,大括号可以省略
    //如果WindowsCondition的实现方法返回true,则注入这个bean    
    @Conditional({WindowsCondition.class})
    @Bean(name = "bill")
    public Person person1(){
        return new Person("Bill Gates",62);
    }

    //如果LinuxCondition的实现方法返回true,则注入这个bean
    @Conditional({LinuxCondition.class})
    @Bean("linus")
    public Person person2(){
        return new Person("Linus",48);
    }
}
  • 标注在类上,一个类中可以注入很多实例,@Conditional标注在类上就决定了一批bean是否注入
@Conditional({WindowsCondition.class})
@Configuration
public class BeanConfig {

    @Bean(name = "bill")
    public Person person1(){
        return new Person("Bill Gates",62);
    }

    @Bean("linus")
    public Person person2(){
        return new Person("Linus",48);
    }
}

@Transient

  • 一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问;
  • transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口;
  • 被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化;

简单地说,@transient就是在给某个javabean上需要添加个属性,但是这个属性你又不希望给存到数据库中去,仅仅是做个非静态的临时变量用一下,不修改已经存在数据库的数据的数据结构。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值