本人最近刚看完《Spring实战 第四版》这本书,也整理写了一些demo。本着复习和分享的心态,题主从今天开始会陆续分享一些Spring的相关教程,欢迎各位来查看评论。
由于网上对Spring IOC的相关概念已经有了很清晰的讲解了,题主在此就不赘述了。这里推荐一篇文章谈谈对Spring IOC的理解,该篇通俗易懂解释了什么是IOC,DI,以及他们之间的区别。
@Component:表明该类会作为普通组件(pojo)类,并告知Spring要为这个类创建Bean。
@Repository:用于标注数据访问层(dao),特殊的@Component注解
@Service:用于标注服务层(Service),特殊的@Component注解
@Controller:用于标注控制层(Controller),特殊的@Component注解
@ComponentScan:默认会扫描与配置类相同的包及其子包,查找带有@Component注解的类,并创建Bean。
可通过basePackages、basePackageClasses属性设置基础包。(推荐使用basePackageClasses,因为basePackages是类型不安全的)
@Configuration:表明此类是一个配置类,该类应该包含在Spring应用上下文中和如何创建Bean的细节。
@Bean:告诉Spring此方法将会返回一个对象,该对象要注册为Spring应用上下文中的Bean。包含了最终产生bean实例的逻辑。
声明bean:〈bean〉标签,id属性设置Bean的名字,class属性设置Bean的所在类,scope属性可指定单例(singleton默认)或多例(prototype)等。
构造器注入:
设值注入(setter):
装配集合:在上诉两种方法中内嵌或
构造器注入主要是依赖于构造方法去实现的,构造方法可以是有参也可以是无参,我们在平常都是通过类的构造方法来创建类对象,以及给他赋值,同样Spring 也可以采用反射的方式,通过构造方法来完成注入注入(赋值),这就是构造器注入的原理。
Setter注入是Spring现在最主流的注入方式,它可以利用Java Bean 规范所定义set/get方法来完成注入,可读性灵活性高,它不需要使用构造器注入时出现的多个参数,它可以把构造方法声明成无参构造,再使用setter注入设置相对应的值,其实也是通过java反射技术去实现的。在这里推荐一个好用的Jar包 Lombok(Lombok简单入门),它可以帮助我们简化一些Java代码的编写。
接口注入是需要调用者必须实现一个指定的接口,然后将接口的实现类注入到接口中,这种方式使用比较少。
1、@Inject:是JSR303中的规范,默认根据类型(Type)进行自动装配的,如果需要按名称进行装配,则需要配合@Named;
2、@AutoWired:是spring自带的注解,默认根据类型(Type)进行自动装配的,如果需要按名称进行装配,则需要配合@Qualifier;
3、@Resource:是JSR250规范的实现,默认根据名称(Name)进行自动装配的,一般会指定一个name属性。
@Import:引入带有@Configuration的java类(整合多个javaConfig)
@ImportResource:导入Spring中的配置文件.xml
在Spring中Bean总共有5种作用域:
① singleton(单例)默认:使用该属性定义Bean时,IOC容器仅创建一个Bean实例,IOC容器每次返回的是同一个Bean实例。
② prototype(原型):使用该属性定义Bean时,IOC容器可以创建多个Bean实例,每次返回的都是一个新的实例。
//指定原型作用域(比@Scope(“prototype”)方式更加安全)
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
③ request:该属性仅对HTTP请求产生作用,使用该属性定义Bean时,每次HTTP请求都会创建一个新的Bean,适用于WebApplicationContext环境。
④ session:该属性仅用于HTTP Session,同一个Session共享一个Bean实例。不同Session使用不同的实例。
//指定会话作用域,需设置代理
@Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES)
代理模式:ScopedProxyMode.INTERFACES --> 基于接口的JDK动态代理
ScopedProxyMode.TARGET_CLASS --> 基于类的CGLib代理
当在XML中通过使用
⑤ global-session:该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个Bean实例。
问题描述:比如说我们有个接口类Animal,而此接口有多个实现类,如Dog,Cat等。此时使用@Autowired注入注解来实现接口注入时,将会抛出NoUniqueBeanDefinitionException异常。
@Autowired
Animal animal;
@Primary注解可与@Component组合用在组件扫描的bean上,也可以与@Bean组合用在Java配置的bean声明中。在XMl中可通过
示例:
@Component
@Primary
public class Dog extends Animal(){ ......... }
@Bean
@Primiary
public Animal dog(){
return new Dog();
}
@Qualifier注解可与@Autowired和@Inject协同使用,在注入时指定想注入的是哪个Bean。所设置的参数为想注入的bean的ID。(参数类型为String类型,紧耦合)
示例:
@Autowired
@Qualifier("dog")
Animal animal;
3、创建自定义的限定符(在自定义的注解中使用@Qualifier注解来标注)
常见元注解(元注解:用于创建注解的注解):
@Target,用于描述注解的使用范围
Constructor:构造器 Field:域 Local_variable:局部变量 Method:方法
Package:包 Parameter:参数 Type:用于描述类、接口(包括注解类型)、enum声明。
@Retention,用于描述注解的生命周期
Source:注解只保留在源文件,当java文件编译成class文件时,注解被遗弃。
Class:注解被保留到class文件,但JVM加载class文件时被遗弃,默认方式。
Runtime:注解不仅保存到class文件,当JVM加载class文件之后仍存在。
@Documented:指明修饰的注解,可以被例如javadoc此类的工具文档化
@Inherited:允许子类继承父类中的注解
示例:
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier
public @interface Dog{
}
@Component
@Dog
public class Dog extends Animal(){ ......... }
软件开发过程一般涉及多个阶段,而每个阶段的环境的配置参数(数据库等)会有所不同。此时我们可以使用profile功能来切换开发环境。
(1)在java中配置profile
@Profile 注解用于标明当前运行环境,只有当对应的profile被激活时,才将profile中所对应的Bean注册到Spring容器中。
(注:没有指定profile的bean始终都会被创建)
(2)在XML中配置profile
通过
(3)激活profile
Spring依赖Spring.profiles.active 和Spring.profiles.default来确定哪个profile处于激活状态。可通过以下方式来设置这两个属性:
作为DispatcherServlet的初始化参数;
作为Web应用的上下文参数;
作为JNDI(java命名与文件夹接口)条目;
作为环境变量;
作为JVM的系统属性;
在集成测试类上,使用@ActiveProfiles注解设置(用来指定运行测试时要激活哪个profile)。
@Conditional注解,用到带有@Bean注解的方法上。若给定的条件计算结果为true则创建,否则不创建。
设置给@Conditional的类可以是任意实现了Condition接口的类型。
public interface Condition {
boolean matches (ConditionContext ctxt , AnnotatedTypeMetadata metadata);
}
ConditionContext是一个接口,大致如下所示:
public interface ConditionContext {
BeanDefinitionRegistry getRegistry(); //可检查Bean定义
ConfigurableListableBeanFactory getBeanFactory(); //可检查bean是否存在,甚至探查bean的属性
Environment getEnvironment(); //可检查环境变量是否存在以及它的值是什么
ResourceLoader getResourceLoader(); //可读取并探查返回的ResourceLoader所加载的资源
ClassLoader getClassLoader(); //借助返回的ClassLoader加载并检查类是否存在
}
AnnotatedTypeMetadata
则能够让我们检查带有@Bean注解的方法上是否有其他注解:
public interface AnnotatedTypeMetadata {
boolean isAnnotated(String annotationType);
Map getAnnotationAttributes(String annotationType);
Map getAnnotationAttributes(String annotationType, boolean classValuesAsString);
MultiValueMap getAllAnnotationAttributes(String annotationType);
MultiValueMap getAllAnnotationAttributes(String annotationType, boolean classValuesAsString);
}
比如,借助isAnnotated()方法,我们能够判断带有@Bean注解的方法是不是还有其他特定的注解。借助其他的方法,我们能够检查@Bean注解的方法上其他注解的属性。