Spring基础梳理

基本原理

spring的基础是IOC和DI,其实IOC和DI是对同一件事从不同的方面进行描述的,两者在spring中是同一件事务。

IOC:控制反转,在这里就是指创建bean的主动权发生了转移,原来是由类主动创建bean,现在类不再创建bean,而是由框架去创建类,所以类的创建权限发生了转移。

DI:依赖注入,在这里是指每个类所需的外部实例,都是先向框架发出需求请求,然后由框架去将创建好的bean注入到类中,所以类是依赖于框架的。

AOP:面向切面,就是将一些公共功能分离出来的一种技术。

IOC/DI/AOP在spring中实现的技术基础是java动态代理和反射技术。

spring模块框架图如下所示:

Spring基础梳理_第1张图片

spring版本变化

spring2.0版本

spring2.5版本

spring3.0 3.1 3.2

spring4.0 4.1 4.2 4.3

spring 5.0 最新版本

其中spring3.x 需要jdk5+  / spring4.x需要jdk6+ 

spring3.x相比于spring2.5.x的区别可分为以下几个方面:模块管理更加细致,分出的包更多;增加了一些新特性,对原来的一些功能进行了增强;针对java5的核心API升级。

spring装配

spring提供了三种装配机制:在xml中进行显示配置;在java中进行显示配置;隐式的bean发现机制和自动装配机制。(注解是java提供的一种机制,允许你对类进行标记,然后在运行时动态操作标记的类,注解机制包括三部分,注解声明,被注解的类,操作注解的代码(通过反射获取类上的注解))

工作中三种方式的梳理:

1.在xml中进行bean的声明和配置;

2.使用javaconfig在java类中进行配置,此处需要使用的@Configuration/@ComponentScan/@Import/@ImportResource注解,其中@Configuration注解表明该类是spring配置类,@ComponentScan表示启动组件扫描,@Import表示导入其他的配置类,@ImortResource表示导入其他的配置文件。

3.混合使用xml和javaconfig,就是使用@Component/@Bean/@Name/@Autowired/@Inject注解配置bean类,同时使用xml配置公共属性,并启动组件扫描。@Component表示该类是一个组件,spring将自动创建该组件实例,@Autowired表示注入组件实例,@Name和@Component功能类似,@Inject和@Autowired功能类似,但@Name和@Inject是Java规范中提供的注解。

java依赖注入和spring注解的不同点和相同点可以参考:

http://www.cnblogs.com/liangxiaofeng/p/6390868.html

http://bhdweb.iteye.com/blog/1663907

http://blog.csdn.net/DL88250/article/details/4838803

当spring引入第三方库中的组件时,此时就不能使用@Component和@Autowired注解了,若使用JavaConfig引入第三方框架时,@Bean注解将会使用到,它一般用在一个方法上,表示方法返回的实例将作为spring中的实例使用,这样就可以在其他类中,像使用spring其他实例那样直接@Autowired即可。

@Autowired和@Resoure的异同点:http://bhdweb.iteye.com/blog/1663907

spring中的profile

在程序开发中,往往有几个好几环境比如:开发环境、测试环境、生产环境,每个环境的数据库配置等信息都不相同,如果每次都通过修改程序和配置文件来切换开发环境,非常容易出现错误,spring的profile就是为了解决不同环境之间切换问题的。

profile在spring3.1中就出现了,不过spring3.1中@Profile只能应用在类上,而在spring3.2中@Profile已经可以在方法上使用。使用如下所示:

@Configuration                                                                                                                         public class DataSourceConfig{                                                                                                              @Bean                                                                                                                                          @Profile("dev")                                                                                                                              public DataSource embeddedDataSource(){}

        @Bean                                                                                                                                          @Profile("prod")                                                                                                                              public DataSource jndiDataSource(){}

}

上面的类中定义了两个profile,但是只有当规定的profile被激活时,相应的bean才会生成。spring在确定激活profile时,需要依赖两个独立的属性,spring.profiles.active和spring.profiles.default。spring的处理机制是,先查找active确定激活的profile,若没有设置active属性,再去查找default。有多种方式设置两个属性:

作为DispatcherServerlet的初始化属性;                                                                                       作为web应用的上下文参数;                                                                                                         作为JNDI条目                                                                                                                                 作为环境变量(需要用到ServletContextListener,重写contextInitialized方法)                              作为jvm的系统属性                                                                                                                       在测试类上,使用@ActiveProfiles注解设置。 

激活示例和xml配置示例可以参考:http://www.cnblogs.com/yw0219/p/5990056.html  http://www.jfox.info/springprofile%E6%BF%80%E6%B4%BB%E5%A4%84%E7%90%86.html

Spring中Bean的特殊用法

条件化的bean

条件化bean指,只有当满足一定条件时才会创建bean,但是在spring4之前,很难实现这一点,但是spring4引入了一个新的@Conditional注解,它可以用到带有@Bean的注解方法上,如果给定的条件计算结果为true,就会创建bean,否则的话,这个bean会被忽略。spring4重构了@Profile,@Profile使用@Conditional注解实现,代码如下所示:

@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE,ElementType.METHOD})                                       @Documented                                                                       @Conditional(ProfileCondition.class)                                                                                    public @interface Profile{    String[] value(); }    

 class ProfileCondition implements Condition{                                                                          public boolean matches(ConditionContext context,AnnotatedTypeMetadata metadata){    if(context.getEnvironment()!=null){    MultiValueMapattrs=metadata.getAllAnnotationAttributes(Profile.class.getName()); if(attrs!=null){                                                                                                                       for(Object value:attrs.get("value")){    if(context.getEnvironment().acceptsProfiles((String[])value)){                                                return true;                                                                                                                                       }                                                                                                                                                     }                                                                                                                                            return false;}}return true;}}

自动装配的歧义性处理

当发生歧义性时,spring提供了多种可供选择的方案来解决该问题。

1.标示首选的bean:当spring遇到歧义性时,spring将会使用首选的bean,而不是其他可选的bean.示例如下所示:

@Component                                                                                                                    @Primary                                                                                                                                public class IceCream implements Dessert{...}

2.限定自动装配的bean:spring提供了@Qualifier限定符用于缩小可选的bean。@Qualifier可以和@Autowired与@Inject协同使用。如下所示:

@Autowired                                                                                                                    @Qualifier("iceCream")                                                                                                                   public class setDessert( Dessert dessert){...}

@Qualifier注解所设置的参数就是想要注入的bean的ID,所有使用@Component注解声明的类都会创建为bean,并且bean的ID为首字目小写的类。

也可以创建自定义的限定符如下所示:

@Component                                                                                                                    @Qualifier("cold")                                                                                                                            public class IceCream implements Dessert{...}

此时IceCreate的bean ID的为:cold.

3.自定义限定符注解

java不允许在同一个条目上重复出现相同类型的多个注解,但是java8注解允许出现重复的注解,只要这个注解本身的定义的时候带有@Repeatable注解就可以,不过@Qualifier注解并没有在定义时添加@Repeatable。@Qualifier可以允许我们定义自己的限定符注解,举例如下所示:

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

下面我们就可以使用@Cold注解代替@Qualifierz("cold")

bean的作用域

spring定义了多种作用域,可以基于这些作用域创建bean.

单例:在整个应用中,只创建bean的一个实例。                                                                       原型:每次注入或者通过spring应用上下文获取的时候,都会创建一个新的bean的实例。       会话:在web应用中为每个会话创建一个bean实例。                                                                 请求:在web应用中,为每个请求创建一个bean实例。

单例是默认的作用域,如果想修改bean的作用域可是使用@Scope注解,示例如下所示:

 @Component                                                                                                                  @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)                                                          public class Cold{.... }

@Scope还有一个proxyMode属性,该属性是解决了将一个会话或请求作用域的bean注入到单例bean中。举例如下所示:

@Component                                                                                                                  @Scope(value=WebApplicationContext.SCOPE_SESSION,proxyMode=ScopedProxyMode.INTERFACES)                                                                   public class ShoppingCart  implements Cart{.... }

@Component                                                                                                                        public class StoreService{                                                                                                                       @Autowired                                                                                                                                    Cart cart;                                    

 }

因为StoreService是单例模式,而ShoppingCart是会话作用域,在spring创建StoreService时,ShoppingCart并不存在,因此通过设置proxyMode属性,spring不会将实际的ShoppingCart注入StoreService中,spring会注入一个代理,只有当StoreService调用cart时,代理会对其进行懒解析并将调用委托给真正的ShoppingCart

你可能感兴趣的:(Spring基础梳理)