开篇先小小感慨一下:人生全都是命运的安排呀,读大学、研究生躲了这么多年的Java,最终都要还回来啊。今天开始学习Spring了,开始搬砖的人生
Spring基础
为了降低Java开发的复杂性,Spring采用了以下4种关键策略:
1、基于POJO的轻量级和最小侵入性编程,所有东西都是bean;
2、通过IOC,依赖注入(DI)和面向接口实现松耦合;
IOC(Inversion of controll 控制反转):对象之间的依赖关系由容器来控制。
DI(Dependency injection 依赖注入):容器通过调用对象提供的set方法或者构造器来建立依赖关系。
IOC是目标,DI是实现手段。
3、基于切面(AOP)和惯例进行声明式编程;
4、通过切面和模版减少样式代码,RedisTemplate,xxxTemplate;
1. set方式注入(较常用)
被注入类提供set方法,配置元素
以下给出一个简单的set方式注入依赖关系的例子:
1、配置xml文件
<bean id="b1" class="com.niuchen.spring.ioc.B"/>
<!--
property表示实用set方法注入依赖关系。
其中,name指定属性名(注入类的对象属性),ref指定属性值(注入的bean的id)
-->
<bean id="a1" class="com.niuchen.spring.ioc.A">
<property name="b" ref="b1"/>
</bean>
2、定义类
// 注入类
public class B {
public B(){
System.out.println("B");
}
public void f1(){
System.out.println("B's f1");
}
}
// 被注入类
public class A {
private B b;//实际应用中更多使用接口定义对象属性,防止代码的修改,此处只为示例
public A(){
System.out.println("A");
}
// B类的set方法,注意方法名不可随意定义
public void setB(B b) {
System.out.println("setB");
this.b = b;
}
public void excute(){
System.out.println("excute");
// 注入依赖后在A类中直接调用B类方法
b.f1();
}
}
3、测试例
public class TestCase {
@Test
public void test3(){
AbstractApplicationContext ac = new ClassPathXmlApplicationContext("ioc.xml");
A a = ac.getBean("a1", A.class);
a.excute();
}
}
2. 构造器方式注入
1.添加相应构造器
public class A {
//接口类型多态,避免了代码的修改
private IB b;
public A(){
System.out.println("A");
}
// 添加相应的构造器
public A(IB b){
System.out.println("A(B)");
this.b = b;
}
public void excute(){
System.out.println("excute");
b.f1();
}
}
2.配置constructor-arg元素
<bean id="b2" class="com.niuchen.spring.ioc2.B"/>
<!-- constructor-arg 配置构造器注入
index指定参数下标
-->
<bean id="a2" class="com.niuchen.spring.ioc2.A">
<constructor-arg index="0" ref="b2"/>
</bean>
3. 自动装配
spring容器根据某种规则自动建立对象之间的依赖关系。
- 默认情况下,容器不会自动装配。
- 可以通过指定autwire属性告诉容器进行自动装配(容器底层仍然通过上文的方式建立依赖关系)。
public class Waiter {
public Waiter(){
System.out.println("Waiter");
}
}
public class Restaurant {
private Waiter wt;
public Restaurant(){
System.out.println("Restaurant");
}
public void setWt(Waiter wt) {
System.out.println("setwt");
this.wt = wt;
}
@Override
public String toString() {
return "Restaurant{" +
"wt=" + wt +
'}';
}
}
配置xml
<bean id="wt" class="com.niuchen.spring.autoIn.Waiter"/>
<!-- autowire:自动装配
byName:容器根据属性名查找对应id的bean,并调用相应set方法注入。
如果没有对应属性名的bean,则注入空值。
byType:容器根据属性类型查找对应类型class的bean,并调用相应set方法注入。
如果没有对应属性名的bean,则注入空值。
如果有多个符合条件的bean则保报错。
constructor:容器根据属性类型查找对应类型class的bean,并调用相应构造器方法注入。
-->
<bean id="rest" class="com.niuchen.spring.autoIn.Restaurant" autowire="byName"/>
junit测试
@Test
// 自动装配
public void test5(){
AbstractApplicationContext ac = new ClassPathXmlApplicationContext("auto.xml");
Restaurant rest = ac.getBean("rest", Restaurant.class);
System.out.println(rest);
}
/**
*测试结果:Waiter
* Restaurant
* setwt
* Restaurant{wt=com.niuchen.spring.autoIn.Waiter@eafc191}
**/
4. 注入基本类型值
配置property属性的value标签。
public class ValueBean {
private String name;
private int age;
public ValueBean(){System.out.println("Value");}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "ValueBean{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
<bean id="vb" class="com.niuchen.spring.value.ValueBean">
<property name="name" value="哈哈哈"/>
<property name="age" value="30"/>
</bean>
5. 注入集合类型值
set方式注入
与基本类型相似,只是配置文件不同,不同类型集合使用对应类型标签赋值,如List使用list标签,Set使用set标签。
<bean id="vb" class="com.niuchen.spring.value.ValueBean">
<property name="name" value="哈哈哈"/>
<property name="age" value="30"/>
<property name="city">
<list>
<value>北京</value>
<value>重庆</value>
<value>上海</value>
</list>
</property>
<property name="interest">
<set>
<value>台球</value>
<value>吉他</value>
<value>音乐</value>
</set>
</property>
<property name="score">
<map>
<entry key="英语" value="60" />
<entry key="数学" value="66"/>
</map>
</property>
<property name="db">
<props>
<prop key="usearname">nc</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
public class ValueBean {
private String name;
private int age;
private List<String> city;
private Set<String> interest;
private Map<String, Double> score;
private Properties db;
public ValueBean(){System.out.println("Value");}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setCity(List<String> city) {
this.city = city;
}
public void setInterest(Set<String> interest) {
this.interest = interest;
}
public void setScore(Map<String, Double> score) {
this.score = score;
}
public void setDb(Properties db) {
this.db = db;
}
@Override
public String toString() {
return "ValueBean{" +
"name='" + name + '\'' +
", age=" + age +
", city=" + city +
", interest=" + interest +
", score=" + score +
", db=" + db +
'}';
}
}
引用注入集合类型的值
对上个例子以引用方式注入的配置方式,该方式配置更整洁灵活,方便集合值重用
<!-- util命名空间 将集合类型的值配置成一个bean -->
<util:list id="cityBean">
<value>北京</value>
<value>重庆</value>
<value>上海</value>
</util:list>
<util:set id="interestBean">
<value>台球</value>
<value>吉他</value>
<value>音乐</value>
</util:set>
<util:map id="scoreBean">
<entry key="英语" value="60" />
<entry key="数学" value="66"/>
</util:map>
<util:properties id="dbBean">
<prop key="usearname">nc</prop>
<prop key="password">123456</prop>
</util:properties>
<!-- 引用的方式注入集合类型的值,方便重用 -->
<bean id="vb2" class="com.niuchen.spring.value.ValueBean">
<property name="city" ref="cityBean"/>
<property name="interest" ref="interestBean"/>
<property name="score" ref="scoreBean"/>
<property name="db" ref="dbBean"/>
</bean>
附加小知识点:
spring表达式:#{bean_id.属性}
Spring容器可以通过Spring表达式获取到其他bean的属性值。
<!-- spring表达式读取其他bean的属性 -->
<bean id="sp1" class="com.niuchen.spring.value.SpelBean">
<property name="name" value="#{vb.name}"/>
<property name="city" value="#{vb.city[1]}"/>
<property name="score" value="#{vb.score.english}"/>
<property name="pageSize" value="#{config.pagesize}"/>
</bean>