ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Spring一些注解功能

2022-01-28 14:02:36  阅读:86  来源: 互联网

标签:功能 Spring public 使用 注解 方法 class EnableConfigurationProperties


1、@Autowired

@Autowired(required=true):表示自动注入时必须能成功注入该对象,否则报错。默认是true@Autowired(required=false):表示自动注入时该对象不是必须注入对象,有就注入,没有也不会报错


2、定制错误页面的json数据

没有自适应效果时应该转发到/error进行自适应响应效果处理


3、@Conditional

@Conditional是Spring4新提供的注解,作用是按照一定条件判断,满足条件才给容器中注册这个bean


4、@Import(重点是两个Import接口的使用)

@Import 参数value接收一个Class数组,将你传入的类以全类名作为id加入IOC容器中

1)、ImportSelector

ImportSelector强调的是复用性,使用它需要创建一个类实现ImportSelector接口,实现方法的返回值是字符串数组,也就是需要注入容器中的组件的全类名。id同样是全类名。

//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
  // 返回值就是导入到容器中的组件全类名
  // AnnotationMetadata:当前标注@Import注解的类的所有注解信息
  public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    return new String[] { "test.spring.ZhangSan", "test.spring.LiSi", "test.spring.WangWu" };
  }
}

2)、ImportBeanDefinitionRegistrar

spring官方就是用这种方式,实现了@Component、@@Service等注解的动态注入机制。定义了一个ImportBeanDefinitionRegistrar的实现类,然后在有@Configuration注解的配置类上使用@Import导入

具体使用:创建一个ImportBeanDefinitionRegistrar的实现类,实现registerBeanDefinitions方法,对组件进行注入。

public class MyBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
  /**
   * @param annotationMetadata 当前标注@Import注解的类的所有注解信息
   * @param beanDefinitionRegistry BeanDefinition的注册类
   */
  public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
    RootBeanDefinition beanDefinition = new RootBeanDefinition(Cat.class);
    beanDefinitionRegistry.registerBeanDefinition("cat",beanDefinition);
  }
}

//结果如下
@Configuration
@Import(value = {MyBeanDefinitionRegistrar.class})
public class MyConfig {
}
 
/**测试结果
beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
beanName: org.springframework.context.event.internalEventListenerProcessor
beanName: org.springframework.context.event.internalEventListenerFactory
beanName: myConfig
beanName: cat
*/


5、@Options

在MyBatis的mapper中使用@Insert注解插入数据信息,但是并没有返回自增主键。如果需要返回自增主键则需要在@Insert后加上@Options注解

@Options(userGeneratedKeys = true, keyProperty = "id")
@Insert("insert into department(departmentName) values(#{departmentName})")
public int insertDept(Department department);

6、Java回调机制

所谓回调:就是A类中调用B类中的某个方法C,然后B类中反过来调用A类中的方法D,D这个方法就叫回调方法。

软件模块之间总是存在着一定的接口,从调用方式上,可以把它们分为三类:同步调用、回调和异步调用。

回调是一种特殊的调用,至于三种方式也有些不同:

  • 同步回调:即阻塞,单向的。
  • 回调:即双向(类似自行车的两个齿轮)。
  • 异步回调:即通过异步消息进行通知。

7、@RequestParam

@RequestParam是将请求参数和控制器方法的形参创建映射关系

@RequestParam注解一共有三个属性:

value:指定为形参赋值的请求参数的参数名

required:设置是否必须传输此请求参数,默认值是true

若设置为true时,则当前请求必须传输value所指定的请求参数,若没有传输该请求参数,且没有设置defaultValue属性,则页面报错400:Required String parameter 'xxx' is not present;若设置为false,则当前请求不是必须传输value所指定的请求参数,若没有传输,则注解所标识的形参的值为null

defaultValue:不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值为""时,则使用默认值为形参赋值。


@Autowired标注在方法上,Spring容器创建当前对象,就会调用方法,完成赋值;方法使用的参数,自定义类型的值从ioc容器中获取。(类似setter方法,参数是什么类型通过自动注入给对象中的属性赋值)


8、@EnableConfigurationProperties

@EnableConfigurationProperties注解的作用是:使使用@ConfigurationProperties注解的类生效。

说明:

  • 如果一个配置类只配置@ConfigurationProperties注解,而没有使用@Component,那么在IOC容器中是获取不到properties配置文件转化的bean。说白了@EnableConfigurationProperties相当于把使用@ConfigurationProperties的类进行了一次注入。
  • 测试发现@ConfigurationProperties@EnableConfigurationProperties关系特别大

测试证明:

@ConfigurationProperties与@EnableConfigurationProperties的关系

@EnableConfigurationProperties文档中解释:当@EnableConfigurationProperties注解应用到你的@Configuration类时,任何被@ConfigurationProperties注解的beans将自动被Environment属性配置。这种风格的配置特别适合与SpringApplication的外部YAML配置进行配合使用。

测试发现:

  1. 使用@EnableConfigurationProperties进行注册
@ConfigurationProperties(prefix = "service.properties")
public class HelloServiceProperties{
    private static final String SERVICE_NAME = "test-service";
    private String msg = SERVICE_NAME;
}

-----------------------------------------------------

@Configuration
@EnableConfigurationProperties(HelloServiceProperties.class)
@ConditionalOnClass(HelloService.class)
@ConditionalOnProperty(prefix = "hello",value = "enable",matchIfMissing = false)
public class HelloServiceAutoConfiguration{
    
}

-----------------------------------------------------

@RestController
public class ConfigurationPropertiesController{
    @Autowired
    private HelloServiceProperties helloServiceProperties;
    @RequestMapping("/getObjectProperties")
    public Object getObjectProperties(){
        System.out.println(helloServiceProperties.getMsg());
        return myConfigTest.getProperties();
    }
}

自动配置设置

service.properties.name=my-test-name
service.properties.ip=192.168.1.1
service.user=keyle
service.port=8080

一切正常,但是HelloServiceAutoConfiguration头部如果不使用@EnableConfigurationProperties,测试访问会报错。

  1. 不使用@EnableConfigurationProperties进行注册,使用@Component注册
@ConfigurationProperties(prefix = "service.properties")
@Component
public class HelloServiceProperties{
    private static final String SERVICE_NAME = "test-service";
    private String msg = SERVICE_NAME;
    public String getMsg(){
        return msg;
    }
    public void setMsg(String msg){
        this.msg = msg;
    }
}

Controller不变,一切正常,如果注释掉@Component则启动报错

由此证明:两种方式都是将被@ConfigurationProperties修饰的类,加载到Spring容器中


9. @Param

作用:

用注解来简化xml配置的时候(比如MyBatis的Mapper.xml中的sql参数引入),@Param注解的作用是给参数命名,参数命名后就能根据名字得到参数值,正确的将参数传入sql语句中(一般通过#{ }的方式,${ }会有sql注入问题)。

实例说明:

  • 使用@Param注解

    Mapper接口方法:

  public int getUserDetail(@Param("userid") int userid);
对应Sql Mapper.xml文件:
<select id="getUserDetail" statememtType="CALLABLE" resultMap="baseMap">
    Exec WebApi_Get_CustomerList #{userid}
</select>

说明:
当你使用了@Param注解来声明参数时,如果使用#{ }或${ }的方式都可以,当你不使用@Param注解来声明参数时,必须使用#{ }方式,如果使用${ }的方式,会报错。

  • 不使用@Param注解

    不使用@Param注解时,最好传递Javabean。在SQL语句里就可以直接引用Javabean的属性,而且只能引用Javabean存在的属性。

    Mapper接口的方法:

  public int getUserDetail(User user);
对应Sql Mapper.xml文件:
<!-- 这里直接引用对象属性即可,不需要对象.属性的方式 -->
<select id="getUserDetail" statementType="CALLABLE" resultMap="baseMap">
    Exec WebApi_Get_CustomerList #{userid}
</select>

10. @Transactional

@Transactional可以说是spring中最常用的注解之一了,通常情况下我们在需要对一个service方法添加事务时,加上这个注解,如果发送unchecked exception,就会发生rollback,最典型的例子如下。

@Service
public class StudentService {
    @Autowired
    StudentDao studentDao;
    
    @Transactional
    public void innerSave(int i) {
        Student student = new Student();
        student.setName("test" + i);
        studentDao.save(student);
        // i=5 会出现异常
        int a = 1 / (i - 5);
    }
}

在调用innerSave(5)时会发生运算异常,导致保存操作回滚,不在此赘述了。

新的需求:循环保存10个学生,发生异常时要求回滚。

我们理所当然的写出了下面的代码,在StudentService.java添加如下方法:

public void outerLooper1() {
    for(int i = 1; i <= 10; i++) {
        try {
            innerSave(i);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

先考虑一下test5这个学生有没有保存呢?

结果:

依然出现了,考虑下问题出在哪儿呢?

其实也好理解,spring中@Transactional的事务开启,是基于接口或者类的代理被创建的。所以在同一个类中一个普通方法outerLooper1( )调用另一个有事务的方法innerSave( ),事务是不会起作用的。要解决这个问题,一般我的做法是写一个帮助类,注入到当前类中,来完成事务操作。

@Autowired
UtilService utilService;

public void outerLooper2() {
    for(int i = 1; i <= 10; i++) {
        utilService.innerSave(i);
    }
}

在Spring中使用事务需要遵守一些规范和了解一些坑点,别想当然。列举一下一些注意点。

在需要事务管理的地方加@Transactional注解可以被应用于接口定义和接口方法、类定义和类的public方法上。

@Transactional注解只能应用到public可见度的方法上。如果你在protected、private或者package-visible的方法上使用@Transactional注解,它也不会报错,但是这个被注解的方法将不会展示已配置的事务设置。

Spring团队建议在具体的类(或类的方法)上使用@Transactional注解,而不要使用在类所要实现的任何接口上。在接口上使用@Transactional注解,只能当你设置了基于接口的代理时它才生效。因为注解是不能被继承的,这就意味着如果正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装。

@Transactional的事务开启,或者是基于接口的或者是基于类的代理被创建。所以在同一个类中一个方法调用另一个有事务的方法,事务是不会起作用的。

了解事务的隔离级别,各个数据库默认的隔离级别是不一样的,在spring中用的是isolation = Isolation.READ_COMMITTED来设置。

了解事务的传播机制,当发生事务嵌套时,按照业务选择对应的传播机制,用propagation = Propagation.REQUIRED来设置。


标签:功能,Spring,public,使用,注解,方法,class,EnableConfigurationProperties
来源: https://www.cnblogs.com/ArosyCatBlogs/p/15852541.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有