Spring的各种注解

一.元注解:——就是定义注解的注解,或者说注解注解的注解

@Retention :用于提示注解被保留多长时间,有三种取值:

public enum RetentionPolicy {
  /**
   * Annotations are to be discarded by the compiler.
   */
  SOURCE,
  /**
   * Annotations are to be recorded in the class file by the compiler
   * but need not be retained by the VM at run time. This is the default
   * behavior.
   */
  CLASS,
  /**
   * Annotations are to be recorded in the class file by the compiler and
   * retained by the VM at run time, so they may be read reflectively.
   *
   * @see java.lang.reflect.AnnotatedElement
   */
  RUNTIME
}

RetentionPolicy.SOURCE 保留在源码级别,被编译器抛弃(@Override就是此类);
RetentionPolicy.CLASS被编译器保留在编译后的类文件级别,但是被虚拟机丢弃;
RetentionPolicy.RUNTIME保留至运行时,可以被反射读取。

@Target: :用于提示该注解使用的地方,取值有:

public enum ElementType {
  /** Class, interface (including annotation type), or enum declaration */
  TYPE,
  /** Field declaration (includes enum constants) */
  FIELD,
  /** Method declaration */
  METHOD,
  /** Formal parameter declaration */
  PARAMETER,
  /** Constructor declaration */
  CONSTRUCTOR,
  /** Local variable declaration */
  LOCAL_VARIABLE,
  /** Annotation type declaration */
  ANNOTATION_TYPE,
  /** Package declaration */
  PACKAGE,
  /**
   * Type parameter declaration
   * @since 1.8
   */
  TYPE_PARAMETER,
  /**
   * Use of a type
   * @since 1.8
   */
  TYPE_USE
}

分别表示该注解可以被使用的地方:
1.(类,接口,注解,enum); 2. 属性域;3.方法;4.参数;5.构造函数;6.局部变量;7.注解类型;8.包

@Documented :表示注解是否能被 javadoc 处理并保留在文档中。

我们熟悉的注解:@Override:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

可以被理解为:
只能使用在方法上,保留在源码级别,被编译器处理,然后抛弃掉。


二.Spring中和bean容器相关的注解

@Repository("标识符") : 指定相应的bean类在ioc容器中的标识符的名称

 @Repository("userRepository")
  public class UserRepositoryImps implements UserRepository{
     @Override
     public void save() {
        System.out.println("UserRepositoryImps save");
     }
 }

定义一个UserRepository接口的实现类,并实现save方法,在这里指定了该bean在IoC中标识符名称为userRepository


@Autowired :其实就是 autowire=byType 就是根据类型的自动注入依赖(基于注解的依赖注入)。
我们先看他的定义:

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

    /**
     * Declares whether the annotated dependency is required.
     * <p>Defaults to {@code true}.
     */
    boolean required() default true;

}

根据元注解我们可以知道:@Autowired注解使用的地方有:属性域,构造函数,方法,参数,注解类型。此注解保留至运行时,可以被反射读取。

其使用方法举例说明:

package com.proc.bean.repository;

public interface UserRepository {

    void save();
}
package com.proc.bean.repository;

import org.springframework.stereotype.Repository;

@Repository("userRepository")  //指定了该bean在IOC容器之中的标识符的名称为userRepository
public class UserRepositoryImps implements UserRepository{

    @Override
    public void save() {
        System.out.println("UserRepositoryImps save");
    }
}
package com.proc.bean.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.proc.bean.repository.UserRepository;

@Service
public class UserService {

    @Autowired  //这里需要一个UserRepository类型的属性,通过@Autowired自动装配方式,从IoC容器中去查找到,并返回给该属性
    private UserRepository userRepository;

    public void save(){
        userRepository.save();
    }
}

测试代码:

ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");

UserService userService=(UserService) ctx.getBean("userService");
userService.save();

返回结果:
UserRepositoryImps save

注意事项:

在使用@Autowired时,首先在容器中查询对应类型的bean

  • 如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据

  • 如果查询的结果不止一个,那么@Autowired会根据名称来查找。

  • 如果查询的结果为空,那么会抛出异常。解决方法时,使用required=false
    若是我们在上面的例子的基础上面再定义一个类,来是想UserRepository接口

package com.proc.bean.repository;

import org.springframework.stereotype.Repository;

@Repository
public class UserJdbcImps implements UserRepository {

    @Override
    public void save() {
        System.out.println("UserJdbcImps save");
    }
}

输出结果:UserRepositoryImps save


@Qualifier : 就是 autowire=byName, @Autowired注解判断多个bean类型相同时,就需要使用 @Qualifier("xxBean") 来指定依赖的bean的id:

同上面的例子:若是想要装载userJdbcImps的实例,除了将字段userRepository名称改成userJdbcImps外,可以提供了一个@Qualifier标记,来指定需要装配bean的名称,代码这样写

 @Autowired
 @Qualifier("userJdbcImps")
 private UserRepository userRepository;

输出结果:UserJdbcImps save


@Resource : 和@Autowired作用相似,也是可以基于注解式的依赖的注入;

@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Resource {

我们可以知道其作用于1.(类,接口,注解,enum); 2. 属性域;3.方法,但是一般其使用在成员属性和Setter方法上面。

注意:

@Resource查询容器之中的对应类型的Bean原则是:
名称优先——>类型次之——>Qualifier约束——>装配失败后异常
但是name属性一旦指定,就只会按照名称进行匹配。

  • @Resource(name=“personDaoBean”)
    

@Autowired查询容器之中的对应类型的Bean原则是:
类型优先——>其次是Qualifier约束——>名称查询——>最后判断是否required
这里的名称查询是将所定义的名称和Bean的name标签进行比较

  • 推荐使用:@Resource注解在字段上,且这个注解是属于J2EE的,减少了与spring的耦合。

@Component : 使用@Component注解在一个类上,表示将此类标记为Spring容器中的一个Bean。

@Repository : 用于将数据访问层(DAO层)的类标识为Spirng Bean。具体只需要将注解标识在DAO类上即可。

@service : 用于将服务层的类标识为Spring Bean,主要用来进行业务的逻辑处理。

@controller : 用于将控制层的类标识为Spring Bean,相当于struts中的action层。
各层级之间的关系图:

各层级之间的关系.png

Spring——功能注解

@Transactional : 使用这个注解的类或者方法表示该类里面的所有方法或者这个方法的事务由spring处理,来保证事务的原子性,即是方法里面对数据库操作,如果失败则spring负责回滚操作,成功则提交操作。

  • 当对Service方法添加事物的时候,加上这个注解,就能保证事物的原子性,当出现unchecked exception的错误,就能够发生回滚。
  • @Transactional注解 可以作用于接口、接口方法、类以及类方法上。由于基于AOP,因此用于方法上时,必须是public方法才会生效,使用到其他类型方法上也不会抛异常,只是会自动忽略。
  • 类中的方法若没有来自外部的方法调用;或者同一个类中有来自外部方法调用却没有添加@Transactional注解,再调用本类内部添加了@Transactional注解的其他方法,事务均不会生效。比如说:方法A添加了注解@Transactional,而B没有,A和B同属于一个类中的两个方法,且A调用了B,那么运行之后,两个事物都不会回滚,因为只有外部的注解会生效,内部的注解不会生效;
注解中定义的属性:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
    @AliasFor("transactionManager")
    String value() default "";

    @AliasFor("value")
    String transactionManager() default "";

    Propagation propagation() default Propagation.REQUIRED;

    Isolation isolation() default Isolation.DEFAULT;

    int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;

    boolean readOnly() default false;

    Class<? extends Throwable>[] rollbackFor() default {};

    String[] rollbackForClassName() default {};

    Class<? extends Throwable>[] noRollbackFor() default {};

    String[] noRollbackForClassName() default {};
}

value()和transactionManager()属性可以指定存在多个TransactionManager的其中一个qualifier属性值或者bean名称。
propagation()属性可以设置Propagation枚举类中的七个传播行为,参考1.2.1,默认为REQUIRED。
isolation()属性可以设置Isolation枚举类中的五个隔离级别,参考1.2.2,默认为DEFAULT。
timeout()设置事务超时时间,默认不超时。
readOnly()设置事务是否是只读事务。
rollbackFor()和rollbackForClassName()设置哪些异常事务会回滚。
noRollbackFor()和noRollbackForClassName()设置哪些异常事务不会回滚。

@Transactional应用举例:

@Transactional
    public String submitOrder(Order order, Model model, HttpSession session) {
        order.setBusertable_id(MyUtil.getUser(session).getId());
        //生成订单
        cartRepository.addOrder(order);
        //生成订单详情
        cartRepository.addOrderDetail(order.getId(), MyUtil.getUser(session).getId());
        //减少商品库存
        List<Map<String,Object>> listGoods =  cartRepository.selectGoodsShop(MyUtil.getUser(session).getId());
        for (Map<String, Object> map : listGoods) {
            cartRepository.updateStore(map);
        }
        //清空购物车
        cartRepository.clear(MyUtil.getUser(session).getId());
        model.addAttribute("order", order);
        return "user/pay";
    }

这是在一个Spring 结合 Mybatis的网上商城项目之中的一段代码,使用@Transactional标注整个方法,因为这个方法添加了,结合Mybatis的对于数据库数据的修改,的事物。使得其中的数据具有原子性和一致性。

@Cacheable : @Cacheable可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。

缓存的作用:我们希望的是,第一次调用这个方法时,返回的数据能被放到服务器端的缓存里,以便于后面要调用这个方法时,能直接从缓存里取到,这样就不用再查数据库占用资源了。而@Cacheable的作用就是这个。

  • 对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。
  • Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,
  • 需要注意的是当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的。

@Cacheable可以指定三个属性,value、key和condition。

  1. value :属性是必须指定的,指定将我们第一次调用的方法的返回的值存储在内存的哪里,就是名称;
  2. key : 用于动态计算密钥的SpEL (Spring Expression Language)表达式。指定Spring缓存方法的返回结果时对应的key的。使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。参默认使用的是方法参数的值;
    注意的是:当我们的指定的key为参数的时候,若是有N个不同的参数调用了相应的方法,就会产生N个缓存。
    使用举例:
@Cacheable(value = "CACHE_BOOK",key = "#root.args[0]", condition = "#language = 1")
public List<Book> getBooksByUsernameAndLanguage(int id, int language) {
     // balabalabala...里面的代码不重要
     return bookList;
}

这里我们使用root.args[0]作为key,表示可以根据所传入的参数:id的不同,建立多个缓存的文件,每个不同的缓存文件的数据都是根据第一次输入id参数的不同,调用方法返回的结果的值。

其实我们这样看来value相当于存储数据的包名,key相当于包下的具体文件。


image.png

3.keyGenerator:key的生成器;可以自己指定key的生成器的组件id, key/keyGenerator:二选一使用(自己配置类)
其实我们了解了key之后,keyGenerator是比较简单的:
无非就是自己定义一个方法来定义我们的key的格式。


    @Bean
     public KeyGenerator springCacheCustomKeyGenerator(){
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                String key = target.getClass().getSimpleName() + "_" +method.getName() + "_" + StringUtils.arrayToDelimitedString(params,"_");
                return key;
            }
        };
    }

  •  @Cacheable(value = "litenfei",key ="springCacheCustomKeyGenerator")
    

4.condition:缓存的条件,表示再怎样的条件下才会进行缓存。如:condition = "#a0>1" 即第一个参数值大于1时才进行缓存

5.unless :否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到的结果进行判断
如: unless = “#a0”:如果第一个参数值是2,则结果不缓存
unless = “#result == null” 结果为null不缓存

以上就是Spring的各种的注释,SpingMVC的注释和SpringBoot的注释将在别的文章之中总结。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容