Top

Spring 的 IoC控制反转 学习笔记



添加 Mavan 依赖

pom.xml
1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>

控制反转及依赖注入

javabean 类

Hello.java
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
29
30
public class Hello {
private int age;
private String msg;
private List list;
private Set set;
private Map<String,Object> map;
private Properties properties;
private Dog dog;

//无参构造方法
public Hello() {
}
//一个参数构造方法
public Hello(int age) {
this.age=age;
}
//二个参数构造方法
public Hello(int age, String msg){
this.msg=msg;
this.age=age;
}

//省略 getter setter 方法...

public void say(){
System.out.println("-----------"+msg);
}

//省略 toString() 方法...
}

省略Dog.java…

xml 配置文件

beans_factory.xml
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<?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 对象给 spring 对象 -->
<!--走有参构造方法-->
<bean id="method1" class="net.crazykid.bean.Hello">
<!-- 依赖注入 -->
<!-- index: 对应构造方法参数的位置 value: 值 -->
<!-- 有多少个constructor-arg就走多少个参数的构造方法,没有就走无参,找不到对应的构造方法就抛异常 -->
<constructor-arg index="0" value="3"/>
<constructor-arg index="1" value="mike"/>
</bean>

<!--走空参构造方法,之后通过set方法设置属性-->
<bean id="method2" class="net.crazykid.bean.Hello">

<!-- 依赖注入 -->
<!--通过 setAge() setMsg() 方法去设置属性-->
<property name="age" value="3"/>
<property name="msg" value="mike"/>

<!--set list的方法-->
<property name="list">
<list>
<value>23</value>
<value>fang</value>
<value>true</value>
</list>
</property>

<!--set map的方法-->
<property name="map">
<map>
<entry key="key1" value="abc"></entry>
<entry key="key2">
<value>ddd</value>
</entry>
</map>
</property>

<!--set prop的方法-->
<property name="properties">
<props>
<prop key="prop1" >
123
</prop>
<prop key="prop2">
2222
</prop>
</props>
</property>

<!--设置对象的方法-->
<!-- ref为引用另外声明的bean的id -->
<property name="dog" ref="dog"/>
</bean>

<bean id="dog" class="net.crazykid.bean.Dog">
<property name="name" value="小狗" />
</bean>

</beans>

注:之后的 XML 配置文件省略头尾标签。

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class testHello {
//通过配置文件获得context
private ApplicationContext context = new ClassPathXmlApplicationContext("beans_factory.xml");

@Test
public void testIoc(){
//取得声明的 id 为 method2 的 bean
//拿回来的是 Object 类型,要强制转换
Hello hello = (Hello) context.getBean("method2");

//调用类里的方法
hello.say(); //输出结果: -----------mike
}
}

自定义 bean 工厂…

bean类

Product.java
1
2
3
4
5
6
7
public class Product {
private String name;
public Product(String name) {
this.name = name;
}
//省略 getter、setter、toString() 方法....
}
ProducteFactory
1
2
3
4
5
6
7
8
public class ProducteFactory {
public static Product createProduct(){
return new Product("产品1");
}
public Product createProduct2(){
return new Product("产品2");
}
}

xml配置文件

beans_factory.xml
1
2
3
4
5
6
<!--静态工厂创建对象-->
<bean id="product1" class="net.crazykid.bean.ProducteFactory" factory-method="createProduct"/>

<!--非静态工厂创建对象-->
<bean id="factory" class="net.crazykid.bean.ProducteFactory" scope="singleton"/>
<bean id="product2" factory-bean="factory" factory-method="createProduct2"/>

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class testFactory {
private ClassPathXmlApplicationContext context;

@Before
public void init() {
context = new ClassPathXmlApplicationContext("beans_factory.xml");
}

@Test
public void test01() {
Product product1 = (Product) context.getBean("product1");
Product product2 = (Product) context.getBean("product2");

System.out.println(product1); //Product{name='产品1'}
System.out.println(product2); //Product{name='产品2'}
}
}

i18n国际化

xml配置文件

beans_factory.xml
1
2
3
4
5
6
7
8
9
<!--国际化标签-->
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">

<!-- 解决中文乱码 -->
<property name="defaultEncoding" value="UTF-8"/>
<!-- value指定语言文件的名称 -->
<property name="basename" value="MessageResource"/>
</bean>

properties 语言文件

MessageResource_en.properties
1
2
hello=hello
hello2=hello {0} welcome to {1}
MessageResource_zh.properties
1
2
hello=你好
hello2=你好 {0} 欢迎来到 {1}

测试类

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
29
30
public class i18nTest {
private ClassPathXmlApplicationContext context;

@Before
public void init() {
context = new ClassPathXmlApplicationContext("beans_factory.xml");
}

@Test
public void Test1() {
ResourceBundleMessageSource source = (ResourceBundleMessageSource) context.getBean("messageSource");
String msg = source.getMessage("hello", null, new Locale("en", "US"));
System.out.println("信息:" + msg); //信息:hello

String msg2 = source.getMessage("hello", null, new Locale("zh", "CN"));
System.out.println("信息:" + msg2); //信息:你好
context.close();
}

@Test
public void Test2() {
ResourceBundleMessageSource source = (ResourceBundleMessageSource) context.getBean("messageSource");
String msg = source.getMessage("hello2", new Object[] {"zhangsan","gz"}, new Locale("en", "US"));
System.out.println("信息:" + msg); //信息:hello zhangsan welcome to gz

String msg2 = source.getMessage("hello2", new Object[] {"张三","广州"}, new Locale("zh", "CN"));
System.out.println("信息:" + msg2); //信息:你好 张三 欢迎来到 广州
context.close();
}
}

监听器(事件)

XML配置文件

beans_listener.xml
1
<bean id="appListener" class="net.crazykid.bean.AppListener"></bean>

bean类

AppListener.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class AppListener implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
//当ApplicationContext初始化或者刷新时触发该事件。
if (event instanceof ContextRefreshedEvent) {
System.out.println("ContextRefreshedEvent事件被触发了");
}
//当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。
else if (event instanceof ContextStartedEvent) {
System.out.println("ContextStartedEvent事件被触发了");
}
//当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。
else if (event instanceof ContextStoppedEvent) {
System.out.println("ContextStoppedEvent事件被触发了");
}
//当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。
else if (event instanceof ContextClosedEvent) {
System.out.println("ContextClosedEvent事件被触发了");
}
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ListenerText {
private ClassPathXmlApplicationContext context;

@Before
public void init() {
context = new ClassPathXmlApplicationContext("beans_listener.xml");
}

@Test
public void test01() {
context.refresh();
context.start();
context.stop();
context.close();
}
}

配置数据源

Mavan 引入c3p0

pom.xml
1
2
3
4
5
6
 <!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>

数据源配置文件 properties

db.properties
1
2
3
4
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/store
jdbc.username=root
jdbc.password=123456

XML配置文件

这里踩了坑:classpath:后面不能有空格!!!!!否则报错!!!!

beans_properties.xml
1
2
3
4
5
6
7
8
9
<!--引用配置文件-->
<context:property-placeholder location="classpath:db.properties"/>

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>

测试类

1
2
3
4
5
6
7
8
9
public class testBeansProperties {
private ApplicationContext context = new ClassPathXmlApplicationContext("beans_properties.xml");

@Test
public void test01() {
Object dataSource = context.getBean("dataSource");
System.out.println(dataSource);
}
}

注解

XML配置文件

beans_zhujie.xml
1
2
3
4
5
6
7
8
<!--让系统能够识别相应的注解-->
<context:annotation-config/>

<!--扫描指定包路径,并且自动注入-->
<context:component-scan base-package="net.crazykid.bean"/>

<!--上面第二个已经包含第一个的功能,所以二选一就行了-->
<!--不写的话是无法识别注解的!-->

bean类

Monkey.java
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
@Component() //此注解表示将javabean声明成一个spring管理的组件,无参的话,beanId为首字母小写同类名,例: context.getBean("monkey");
//@Component(value = "customName") //有参的话,就是自定义beanId,例:context.getBean("customName");
public class Monkey{
private String name;
private MonkeyDaddy monkeyDaddy;

public Monkey() {
}

public Monkey(String name) {
this.name = name;
}

public String getName() {
return name;
}

@Value("猴子") //等同于 xml 里的 <property name="name" value="猴子"/>
public void setName(String name) {
this.name = name;
}

public MonkeyDaddy getMonkeyDaddy() {
return monkeyDaddy;
}

//@Resource(name = "monkeyDaddy") //寻找 beanId 为 monkeyDaddy 的类注入
@Autowired //自动装配,意思是自动寻找MonkeyDaddy类注入
@Qualifier("monkeyDaddy") //指定注入的BeanId,要注入的类有多个实现类的时候有用
public void setMonkeyDaddy(MonkeyDaddy monkeyDaddy) {
this.monkeyDaddy = monkeyDaddy;
}

@PostConstruct //此注解标识初始化时调用
public void OnConstruct() {
System.out.println("Monkey类被构造了");
}

@PreDestroy //此注解标识销毁时调用
public void OnDestroy() {
System.out.println("Monkey类被销毁了");
}

@Override
public String toString() {
return "Monkey{" +
"name='" + name + '\'' +
", monkeyDaddy=" + monkeyDaddy +
'}';
}
}
MonkeyDaddy.java
1
2
3
4
5
6
7
8
9
10
11
@Component()
@Primary //当满足条件的情况下,优先会用@Primary注解的javabean
public class MonkeyDaddy{
private String name;
//..省略部分方法

@Value("猴子的爸爸")
public void setName(String name) {
this.name = name;
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
public class testZhujie {
private ClassPathXmlApplicationContext context;

@Before
public void init() {
context = new ClassPathXmlApplicationContext("beans_zhujie.xml");
}

@Test
public void test01() {
System.out.println(context.getBean("monkey"));
}
}

输出结果:

Monkey类被构造了
Monkey{name=’猴子’, monkeyDaddy=MonkeyDaddy{name=’猴子的爸爸’}}


 发表评论

文明评论,请勿灌水。为防止恶意评论,请登录账号后发表评论