spring3.0版本后加入,是spring支持注解开发的一个标志
表明当前类为spring的一个配置类,用来替代applicationContext.xml
本质为一个@Component注解,被此注解修饰的类,也会被存入spring的Ioc容器
用于注解驱动开发时用于编写配置的类,@Configuration通常用于主配置类上
注意: 注解驱动开发时,如果构建Ioc容器用的是传入字节码的构造函数,此注解可以省略,但如果使用传入包的构造函数,则不能省略
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
/*Explicitly specify the name of the Spring bean definition associated with the @Configuration class. If left unspecified (the common case), a bean name will be automatically generated.
The custom name applies only if the @Configuration class is picked up via component scanning or supplied directly to an AnnotationConfigApplicationContext. If the @Configuration class is registered as a traditional XML bean definition, the name/id of the bean element will take precedence.
Returns:
the explicit component name, if any (or empty String otherwise)
See Also:
AnnotationBeanNameGenerator*/
@AliasFor(annotation = Component.class)
String value() default ""; // 用于存入spring的Ioc容器中Bean的id
}
在入门中,由于没有applicationContext.xml,不能在xml中配置spring常见容器中要扫描的包,使自己编写的类无法加入到Ioc容器,此时可以用注解来代替配置文件
/**
* spring注解驱动开发的配置类
* 相当于applicationContext.xml
* @author 刘淳
*/
@Configuration
public class SpringConfiguration {
}
/**
* 测试@Configuration注解
* @author 刘淳
*/
public class SpringConfigurationTest {
/**
* 测试方法
*/
public static void main(String[] args) {
//扫描包方式创建容器 需在配置类上使用@Configuration注解
//1.创建容器
AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext("config");
//2.获取对象
SpringConfiguration configuration = applicationContext.getBean(SpringConfiguration.class);
//3.输出结果
System.out.println(configuration);
//config.SpringConfiguration$$EnhancerBySpringCGLIB$$79a0bbb9@70b0b186
//传入配置类字节码方式创建容器 @Configuration可省略
//1.创建容器
AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(SpringConfiguration.class);
//2.获取对象
SpringConfiguration configuration = applicationContext.getBean(SpringConfiguration.class);
//3.输出结果
System.out.println(configuration);
//config.SpringConfiguration@6325a3ee
}
}
用于指定创建容器时要扫描的包,扫描位置可以指定扫描的包名,也可指定扫描的类的字节码(扫描该类所在包及其子包)。
支持定义扫描规则,例如包含或排除某些部分
支持自定义Bean的命名规则
注解驱动开发时,要想spring将自己编写的类添加到Ioc容器中,就需要使用该注解实现组件扫描
PS:spring4.3版本后加入@ComponentScans注解,支持配置多个@ComponentScan
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
/**
*用于指定要扫描的包,spring会扫描指定的包及其子包下的所有类
*/
@AliasFor("basePackages")
String[] value() default {};
/**
*与value互为别名引用
*/
@AliasFor("value")
String[] basePackages() default {};
/**
*指定具体要扫描的类的字节码 会扫描该类所在的包及其子包
*/
Class<?>[] basePackageClasses() default {};
/**
*指定扫描Bean对象存入容器时的命名规则,可以自定义命名规则(实现BeanNameGenerator接口)
*/
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
/**
*处理并转换检测到的Bean的作用范围
*/
Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
/**
*指定Bean生成时的代理方式
*默认为Default(等同于No),不使用代理
*/
ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
/**
*用于指定符合组件检测条件的类文件,默认为包扫描下的 **/*.class
*/
String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
/**
*是否对带有@Component @Repository @Service @Controller注解的类开启检测,默认是开启的
*/
boolean useDefaultFilters() default true;
/**
*自定义组件扫描的过滤规则,用以扫描组件
*/
Filter[] includeFilters() default {};
/**
*自定义组件的排除规则
*/
Filter[] excludeFilters() default {};
/**
*组件扫描时是否采用懒加载,默认不开启
*/
boolean lazyInit() default false;
/**
*过滤规则
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({})
@interface Filter {
/**
*FilterType有5种类型:
ANNOTATION, 注解类型 默认
ASSIGNABLE_TYPE,指定固定类
ASPECTJ, ASPECTJ类型
REGEX,正则表达式
CUSTOM,自定义类型
*/
FilterType type() default FilterType.ANNOTATION;
/**
*要过滤的类类的字节码文件
*/
@AliasFor("classes")
Class<?>[] value() default {};
/**
*等同于classes
*/
@AliasFor("value")
Class<?>[] classes() default {};
String[] pattern() default {};
}
}
要将使用了@Component及其衍生注解配置的Bean加入Ioc容器,就得使用@ComponentScan
注解驱动开发JaveEE项目时,Ioc容器分为 RootApplicationContextServletApplicationContext
我们不希望Controller加入到Root容器中,可以使用过滤规则排除@Controller注解配置的Bean
/**
* spring的配置类
* @author 刘淳
*/
@Configuration
@Import(JdbcConfig.class)
@PropertySource("classpath:jdbc.properties")
@ComponentScan(value="com.liuchun",excludeFilters=@ComponentScan.Filter(type = FilterType.ANNOTATION,classes =Controller.class))
public class SpringConfiguration {
}
写在方法上,将当前方法的返回值存入spring的Ioc容器
写在注解上,作为元注解使用
在基于注解的配置中,如果要存入容器的Bean不是我们写的类,此时无法在类上添加@Component注解,需要使用@Bean加入容器
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
/**
*指定存入spring容器中Bean的标识
*支持指定多个标识,默认值为当前方法名称
*/
@AliasFor("name")
String[] value() default {};
/**
*spring4.3.3版本后加入,和name属性一样
*/
@AliasFor("value")
String[] name() default {};
/**
*spring5.1开始已弃用
*/
@Deprecated
Autowire autowire() default Autowire.NO;
/**
*用于指定是否支持自动按类型注入到其它Bean中,只影响@Autowired注解的使用
*默认值为True 允许使用自动按类型注入
*/
boolean autowireCandidate() default true;
/**
*用于指定初始化方法
*/
String initMethod() default "";
/**
*用于指定销毁方法
*/
String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}
//将JdbcTemplate加入到容器中
@Bean("jdbcTemplate")
public JdbcTemplate createJdbcTemplate(DataSource dataSource){
return new JdbcTemplate(dataSource);
}
写在类上,与注解驱动配置类一起使用,引入其他配置类
使用此注解后,可以和早期xml配置一样,分别配置不同内容,使配置更加清晰
指定此注解后,被引入的类上不可以再使用@Configuration,@Compnent等注解
注解驱动开发时,由于配置项过多,如果都写在一个类里,配置结构和内容将杂乱不堪,使用此注解可以把配置项进行分门别类进行配置
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
/**
*用于指定其它配置类的字节码,至此指定多个配置类
*/
Class<?>[] value();
}
/**
* spring配置类
* @author 刘淳
*/
@Configuration
@Import(JdbcConfig.class) // 引入Jdbc的配置类
@ComponentScan("com.liuchun")
public class SpringConfiguration {
}
指定读取资源文件的位置
支持properties以及xml文件
通过YAML解析器,配合自定义PropertySourceFactory可实现解析yml配置文件
使用注解驱动后,xml配置文件就没有了,此时如果一些配置直接写在类中,会造成和java源码的紧密耦合,修改有极大困难,而用properties或yml来配置就会变得很灵活,此时就需要此注解来将其引入
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(PropertySources.class)
public @interface PropertySource {
/**
*指定资源的名称,未指定则根据基础资源描述生成
*/
String name() default "";
/**
*指定资源位置,可以为类路径或文件路径
*/
String[] value();
/**
*是否忽略资源文件不存在,默认为false,当资源文件不存在spring启动将报错
*/
boolean ignoreResourceNotFound() default false;
/**
*指定解析文件使用的字符集,有中文时需指定中文的字符集
*/
String encoding() default "";
/**
*指定读取对应资源文件的工厂类,默认为PropertySourceFactory
*/
Class<? extends PropertySourceFactory> factory() default PropertySourceFactory.class;
}
连接数据库的信息如果直接写在JdbcConfig中,需要修改时就面临修改源码的问题
可选择使用@PropertySource和SpringEL表达式,就可将配置存入properties文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=lc20000925
/**
* 连接数据库的配置
* @author 刘淳
*/
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
}
/**
* spring配置类
* @author 刘淳
*/
@Configuration
@Import(JdbcConfig.class)
@PropertySource("classpath:jdbc.properties")
@ComponentScan("com.liuchun")
public class SpringConfiguration {
}
用于指定某个类的创建依赖的Bean对象先创建
使用此注解可指定Bean的加载顺序(在基于注解配置中,是按照类中方法的书写顺序决定的)
在观察者模式中,分为事件,事件源和监听器。
一般情况下,我们的监听器负责监听事件源,当事件源触发事件时,监听器捕获并作出处理
因此监听器的创建应在事件源之前,此时可以用@DependsOn实现
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DependsOn {
/**
*指定Bean的唯一标识,被指定的Bean会在当前Bean创建前加载
*/
String[] value() default {};
}
/**
* @author 刘淳
*/
@Component
public class CustomerListener {
public CustomerListener(){
System.out.println("监听器创建了。。。");
}
}
/**
* @author 刘淳
*/
@Component
@DependsOn("customerListener")
public class Customer {
public Customer(){
System.out.println("事件源创建了。。。");
}
}
指定单例Bean对象的创建时机
不使用此注解时,单例对象的生命周期与容器相同
使用此注解后,单例对象的创建时机变成了第一次使用时创建
实际开发中当Bean为单例对象时,并不是每个都需要一开始就加载到Ioc容器中,有些可以在使用时再加载,此注解即可完成该需求(此注解只对单例Bean对象起作用,指定@Scope的prototype后失效)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR,
ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Lazy {
/**
*指定是否采用延迟加载 默认开启
*/
boolean value() default true;
}
根据条件选择注入的Bean对象
开发时往往使用多平台来测试,例如测试数据库分别部署于Linux和Windows上,使用此注解可以根据工程环境选择连接的数据库
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
/**
*用于提供一个Condition接口的实现类,实现类中编写具体代码实现注入的条件
*/
Class<? extends Condition>[] value();
}
这四个注解都用于修饰类,把当前类创建一个对象并存入Spring的Ioc容器中
实例化时首选默认无参构造函数,同时支持带参构造,但参数依赖必须有值,否则抛出异常
当需要把自己编写的类加入到Ioc容器中时,可以使用以上四个注解实现
@Component注解通常用于非三层对象中
@Contorller,@Service,@Repository 三注解一般针对三层对象使用,提供更加精准的语义化配置
spring注解驱动开发时,如果类没有加入到Ioc容器,那么里面的属性和方法上的注解都不会被解析
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
/**
*用于指定存入容器时Bean的id 默认值为当前类的名称
*/
String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
@AliasFor(annotation = Component.class)
String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
@AliasFor(annotation = Component.class)
String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
@AliasFor(annotation = Component.class)
String value() default "";
}
正确的方式1:使用默认构造函数
/**
* 用于记录系统日志
* @author 刘淳
*/
@Component
public class LogUtil {
/**
* 默认无参构造函数
*/
public LogUtil(){
}
}
正确的方式2:在构造函数中注入一个已经在容器中的bean对象。
/**
* 此处只是举例:使用JdbcTemplate作为持久层中的操作数据库对象
* @author 刘淳
*/
@Repository("userDao")
public class UserDaoImpl implements UserDao{
private JdbcTemplate jdbcTemplate ;
/**
* 此时要求容器中必须有JdbcTemplate对象
* @param jdbcTemplate
*/
public UserDaoImpl(JdbcTemplate jdbcTemplate){
this.jdbcTemplate = jdbcTemplate;
}
}
正确的方式3:在构造函数中注入一个读取配置文件获取到的值。
/**
* 用于记录系统日志
* @author 刘淳
*/
@Component
public class LogUtil {
/**
* 构造时,注入日志级别
* @param logLevel
*/
public LogUtil(@Value("${log.level}")String logLevel){
System.out.println(logLevel);
}
}
错误的方式:由于logLevel没有值,所以运行会报错。
/**
* 用于记录系统日志
* @author 刘淳
*/
@Component
public class LogUtil {
/**
* 构造时,注入日志级别
* @param logLevel
*/
public LogUtil(String logLevel){
System.out.println(logLevel);
}
}
自动按照类型注入
当Ioc容器中有且只有一个类型匹配时可以直接注入成功
当超过一个匹配时,则使用变量名称(若写在方法上则为方法名称)作为Bean的id,在符合类型的Bean中再次匹配,匹配上则注入成功。
匹配不上时,根据required属性的取值决定是否报错
自己写的类中注入依赖Bean对象时,可以采用此注解
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER,
ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
/**
* 是否必须注入成功 默认值为true
* 取值为true时,注入不成功将会报错
*/
boolean required() default true;
}
/**
* 使用Jdbc作为持久层中的操作数据库对象
* @author 刘淳
*/
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao{
@Autowired
private JdbcTemplate jdbcTemplate ;
}
当使用自动按类型注入时,有多个类型匹配的时候,就可以使用此注解明确注入哪个Bean对象
通常情况下必须配置@Autowired注解一起使用
当容器中有两个类型相同的Bean对象的时候,就可以使用此注解注入
如果把要注入的变量名称改为和要注入Bean的id一致则可以不使用此注解
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER,
ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {
/**
* 指定Bean的唯一标识
*/
String value() default "";
}
此注解来源于JSR规范(Java Specification Requests),用于找到依赖的组件注入到应用
利用了JNDI(Java Naming and Directory Interface Java 命名目录接口 J2EE规范之一)技术查找所需的资源
1. 所有属性都不指定,默认按照byType的方式装配Bean对象
2. 指定name,不指定type,则采用byName装配Bean对象
3. 不指定name,指定type,按照byType装配Bean对象
4. name,type都指定,两个都校验,有任何一个不符合条件就报错
当我们某个类的依赖Bean在Ioc容器中存在多个的时候,可以使用此注解指定特定的Bean对象注入
等同于@Autowired配合@Qualifier注入
@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
/**
*资源的JNDI名称 在spring注入时指定Bean的唯一标识
*/
String name() default "";
/**
*引用指向的资源名称 它可以使用全局JNDI名称链接到任何兼容的资源
*/
String lookup() default "";
/**
*指定Bean的类型
*/
Class> type() default java.lang.Object.class;
/**
*指定资源的身份验证类型,它只能为任何受支持类型的连接工厂的资源指定此选项,而不能为其它类型的资源指定此选项
*/
enum AuthenticationType {
CONTAINER,
APPLICATION
}
AuthenticationType authenticationType() default
AuthenticationType.CONTAINER;
/**
*指定此资源是否可以在此组件和其它组件之间共享
*/
boolean shareable() default true;
/**
*指定资源的映射名称
*/
String mappedName() default "";
/**
*指定资源的描述
*/
String description() default "";
}
用于注入基本类型和String类型的数据
支持spring的EL表达式,可通过${} 的方式获取配置文件(properties,xml,yml)中的数据
实际开发中,连接数据库的配置等可以用配置文件保存,此时读取配置文件可以使用EL表达式读取
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER,
ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
/**
*指定注入的数据或EL表达式
*/
String value();
}
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=lc20000925
/**
* 连接数据库的配置
* @author 刘淳
*/
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean("dataSource")
public DataSource createWindowsDataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
用于建立依赖关系,与@Resource和@Autowired作用一样
使用前需导入坐标:
javax.inject
javax.inject
1
区别:
@Autowired:来源于spring框架自身,默认为byType自动装配,当配合了@Qualifier注解后,由@Qualifier实现byName装配。有一个required属性,用于指定是否必须注入成功
@Resource:来源于JSR-250规范,在没有指定name属性时为byType自动装配,指定name后采用byName方式自动装配
@Inject:来源于JSR-330规范(Jcp给出的官方标准反向依赖注入规范),不支持任何属性,但可以配合@Qualifier或@Primary注解使用。默认byType装配,指定JSR-330规范中的@Named注解后变为byName装配
使用@Autowired注解的地方,都可以替换成@Inject
可以出现在方法,构造函数和字段上
JRE无法决定构造方法注入的优先级,规范中规定类中只能有一个构造方法带@Inject
/**
* 第一种写法: 写在字段上
* 此处只是举例:使用Jdbc作为持久层中的操作数据库对象
* @author 刘淳
*/
@Repository("userDao")
public class UserDaoImpl implements UserDao{
@Inject
private JdbcTemplate jdbcTemplate ;
}
/**
* 第二种写法:写在构造函数上
* 此处只是举例:使用Jdbc作为持久层中的操作数据库对象
* @author 刘淳
*/
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao{
private JdbcTemplate jdbcTemplate ;
/**
* 此时要求容器中必须有JdbcTemplate对象
*/
@Inject
public AccountDaoImpl(JdbcTemplate jdbcTemplate){
this.jdbcTemplate = jdbcTemplate;
}
}
/**
* 第三种写法:配合@Named注解使用
* 此处只是举例:使用Jdbc作为持久层中的操作数据库对象
* @author 刘淳
*/
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao{
@Inject
@Named("jdbcTemplate")
private JdbcTemplate jdbcTemplate ;
}
指定Bean的注入优先级,被@Primary修饰的Bean对象优先注入
依赖对象有多个存在时,使用此注解表示优先使用被@Primary注解的Bean,当不存在时使用其它Bean对象
AccountServiceImpl中的accountDao将会优先注入AccountDaoImpl2,当要注入AccountDaoImpl时,可用@Qualifier("accountDaoImpl1")注入
/**
* @author 刘淳
*/
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
public void save(){
System.out.println(accountDao);
}
}
/**
* 此处只是举例:使用Jdbc作为持久层中的操作数据库对象
* @author 刘淳
*/
@Repository("accountDaoImpl1")
public class AccountDaoImpl implements AccountDao{
@Override
public String toString() {
return "accountDaoImpl1";
}
}
/**
* 此处只是举例:使用Jdbc作为持久层中的操作数据库对象
* @author 刘淳
*/
@Repository("accountDaoImpl2")
@Primary
public class AccountDaoImpl2 implements AccountDao{
@Override
public String toString() {
return "accountDaoImpl2";
}
}
用于指定Bean对象的作用范围
Bean对象默认都是单例的,当必须配置为多例时,可用该注解实现
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
/**
* 指定作用范围的取值 默认值为""
* spring初始化容器时会借助ConfigurableBeanFactory中的类成员:
* String SCOPE_SINGLETON = "singleton"
*/
@AliasFor("scopeName")
String value() default "";
/**
* 与value互为别名引用
*/
@AliasFor("value")
String scopeName() default "";
/**
* 指定Bean对象代理方式,指定的是ScopedProxyMode枚举的值
* DEFAULT:默认值。(就是NO)
* NO:不使用代理。
* INTERFACES:使用JDK官方的基于接口的代理。
* TARGET_CLASS:使用CGLIB基于目标类的子类创建代理对象。
*/
ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}
指定Bean对象的初始化方法
Bean对象创建完成后,如需要对成员进行初始化操作,可以使用此注解配置初始化方法
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}
指定Bean对象的销毁方法
在Bean对象销毁之前,进行一些清理操作
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PreDestroy {
}