0%

Spring_基础装配

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登录不了?信任该网站之后再登录。