Spring框架最基础的技术就是:依赖注入(DI) , AOP技术;
Spring的很多功能和特性都是基于这两个技术实现的;
下面我将总结下Spring依赖注入(DI)方面的知识,增加自己的理解和记忆。
Spring配置Bean的几种方式 1:隐式的Bean发现机制和自动装配;
2:在Java 中显示配置;
3:XML 中显示配置;
4:混合配置;
前3种配置方式,尽可能的使用自动配置(1),当自动配置不能满足的时候才用Java config(2)显示配置;
粗略的优先级
自动装配 > 显示配置 > Xml配置
通常的JAVA依赖注入,构造注入,接口注入,setter方法注入,都是将对象的源 ,通过一定的方式注入到目的类中。Spring中的依赖注入,开发者只需要关注源和目的类,然后声明式的设置源和目的类,Spring 框架提供了强大的声明式配置达到开发者想要的依赖注入效果;
自动装配 Spring 从两个角度来实现自动化装配:
组件扫描(ComponentScaning):Spring 会自动发现应用上下文中所创建的bean; 自动装配(Autowiring):Spring 自动满足bean 之间的依赖,Spring 会自动将唯一关系匹配的bean关联上;
例:
1 2 3 4 5 6 7 8 @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) @Component(value = "anb") public class AnnotationBean { public void print(String str) { System.out.println("AnnotationBeans " + str); } }
设置依赖注入的源:
使用@Component注解 标注类,这样Spring 就知道该类是组件类,会自动创建; Spring 针对不同用途也提供了几个特定用途的注解;
分别是:
1 2 3 4 @Configuration 如果通过Java Config 的装配方式的话,会有一个Config类,这个类也需要被Spring扫描到; @Repository 用于标注 DAO层链接数据库的类; @Service 用于标注 Service层的类 @Controller 用于标注 Controller层的类
解释:
@Scope : 作用域 默认Spring自动创建的组件类是单例模式的; ConfigurableBeanFactory.SCOPE_PROTOTYPE 是每次使用都创建不同新的实例;可以修改Scope的属性进行相应的设置;
@Component 组件注解 ,这里的value是给组件设置名字,如果不设置,Spring 会将第一个字母小写的类名当做组件的名字;
如果用在Config类上@Component标注只是将这些类标记为组件类,还需要使用 @ComponentScan 告诉Spring启用组件扫描;
这里需要注意下扫描的路径,默认是扫描Java config类的那个目录,如果需要跨目录,一定需要配置。@ComponentScan也有很多属性可以配置。
到这里,@Component标注的组件类有了,@ComponentScan也启用了,Spring 容器(上下文)就会自动创建这些类的实例;
但这些实例只有容器持有,没被任何地方使用;
@Autowiried自动装配就是将这些组件类实例 注入到需要的地方;
下面是完整的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Component public class L2Bean { public void print() { System.out.println("autowired 成功"); } } @Configuration @ComponentScan(basePackages = {"com.conan.beans"}) // 我这里存在跨目录 public class L2Config { } @RunWith(value = SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = L2Config.class) public class TestConfig { @Autowired private L2Bean l2Bean; //这里是父类型,接口类型都能接受 @Test public void testAutowired(){ l2Bean.print(); } }
@ComponentScan @ComponentScan 默认是扫描类当前所在的包下的所有内容
扫描的形式:扫描basePackages , 扫描basePackageClasses等
其中basePackageClasses的扫描形式,可以给所有要扫描的类添加一个空接口,专门用来做扫描标记;
@Autowiried Spring 的@Autowiried ,能把容器中唯一能匹配的实例匹配上,即使目标处用的是接口类型的实例,如果有多个可以匹配就会出错,这个就要用到后面更高级的声明了; @Autowiried 可以作用在成员变量,构造方法,setter方法上(setter方法不用是严格意义上的setter方法,只要是赋值的方法上);
作用在成员变量和setter方法上,是直接提供成员变量; 作用在构造上是提供构造需要的参数;
如果@Autowiried 所注解的成员变量不是必要的, 可以使用 required 属性设置为false;值得注意的是,此时,这个成员变量使用时要记得做判null;
还有另外一种 注解方式:@Name 类似@Component , @Inject 类似@Autowiried;
Spring 自动装配额外特性 如果Spring 容器中同类型的Bean 有多个,如果定义一个该类型的集合,并使用@Autowired 标注,Spring 会把容器中所有和该Bean同类型的bean装配到对应类型的集合中!!!!!
这个特性在Spring 的功能的源码中可以看到,比如Spring MVC的 ViewResolver;
Java 中显示配置 虽然推荐使用 Spring的自动装配,但是如果我们用到了第三方的类的时候,就没法在人家的类上使用@Component了。此时我们就要使用在Java Config中显示配置;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // 源 @Configuration() public class L3Config { @Bean public L2Bean creatL2Bean(){ return new L2Bean(); } } // 使用 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = L3Config.class) public class TestConfig2 { @Autowired L2Bean l2Bean; @Test public void testL2JavaConfig(){ l2Bean.print(); } }
@Bean 在Java Config中显示配置,需要使用 @Bean 注解;@Bean注解通常配合@Configuration使用(如果不需要扫描其他的组件类,那就不用使用@ComponentScan了);
@Bean作用在方法上,可以通过 name / value 属性给实例命名(类似ID的意思),默认是使用方法名作为名称;
@Bean 还有 initMethod ,destroyMethod 属性,initMethod可以对象实例化只会调用该对象的方法,方法不需要”()“ 如这里的 @Bean(initMethod = “print”);destroyMethod同理;
前面讲 自动匹配的时候,有说的@Scope; 当使用 Java Config方式配置的时候, @Bean 是没有配置作用域的属性的,如果需要配置作用域,也是需要借助@Scope 注解;
XML 装配 前面两种装配方式,创建了一个使用@Configuration标注的类,在XML配置中,需要创建一个XML文件,并且要以元素为根;
如果换一种理解方式;可以把@Configuration标注的类理解为就是一个XML配置;
下面是最简单的使用方式,XML配置中负责Spring 容器中的配置,@Autowired负责装配;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean class="com.conan.beans.L2Bean"/> </beans> @RunWith(BlockJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:spring-xml-config.xml"}) public class TestXMlConfig { @Autowired L2Bean l2Bean; @Test public void testXmlConfig() { l2Bean.print(); } }
其实在 是可以配置id 属性的,如果没有配置的话,Spring 会根据全限定类名来进行命名;
这里L2Bean 实例的全限定名称:”com.conan.beans.L2Bean#0“ ,其中”#0“ 是一个计数的形式,如果有声明了另外一个L2Bean,就会是”#1“的形式;
可以通过如下代码测试出来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @RunWith(BlockJUnit4ClassRunner.class) public class TestXMlConfig { L2Bean l2Bean; private ClassPathXmlApplicationContext context; @Before public void before() { context = new ClassPathXmlApplicationContext("classpath:spring-xml-config.xml"); } // @Autowired // private ApplicationContext context; 也可以通过自动装配方式获取 上下文(容器) @Test public void testXmlConfig() { l2Bean = (L2Bean) context.getBean("com.conan.beans.L2Bean#0"); l2Bean.print(); } }
xml方式的装配,只能是通过构造方法的方式来实现,对象的创建;
如果需要配置属性,可以通过构造穿入,或者setter方法(非严格意义上的)传入;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="com.conan.beans.L3Bean"> <constructor-arg name="name" value="Conan"/> </bean> <bean class="com.conan.beans.L2Bean"> <property name="name" value="Conan2"/> </bean> </beans>
混合装配 以JavaConfig 为主的 混合装配 1 2 3 4 5 6 @Configuration @Import(CDPlayerConfig.class) // 引入别的Java config @ImportResource("classpath:cd-config.xml") // 引入别的XMl config public class JavaConfigMixConfig { }
以XML 为主的 混合装配 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config>com.conan.aopbaseconfig.L2Config</context:annotation-config> // 引入别的Java config 方式1 <!--<bean class="com.conan.aopbaseconfig.L3Config"/>--> // 引入别的Java config 方式2 <!--<import resource="spring-xml-mix.xml"/>--> // 引入别的XMl config </beans>
C 标签 和 P 标签 Spring 3.0 之后引入了C标签 和 来精简XML 配置
C 标签命名空间属性的组成方式:
c:cd-ref=”xxxId“ c:name=”attr“
c : 命名空间前缀; cd : constructor 构造器参数名; —ref : 注入bean的引用; 如果不是引用 : c:name=”attr“ 直接属性名字,和对应的参数值 xxxId : 要注入bean的id;
:可以专票集合 list set xxxxx …
[ … ]
Spring 提供了 P 标签
P 标签命名空间属性的组成方式:
p:attr-ref=”xxx” p:attr=”attrValue”
p:命名空间前缀; attr :属性名; -ref : 注入bean的引用;如果不是注入引用,和C标签一样; xxx : 要注入bean的id;
XML 方式不推荐使用,所以这里粗略总结下而已;
GitHub登录不了 ?信任该网站之后再登录。