spring-ioc原理
三月 07, 2019
最初java调用
1
2
3
4
5package com.test;
public class UserService {
public void add(){};
}要调用UserService类中的add()方法:
1
2
3
4
5
6
7
8package com.test;
public class UserServlet {
public void addUser() {
UserService user = new UserService();
user.add();
}
}其他类用到,也是同样的写法,这是最初java调用某个类的方法的写法,如果类的方法或者类名要改定,那么必须把调用到改类的地方全部都改写一遍,这样耦合度太高,于是使用工厂模式来进行解耦合,我们可以这样写:
1
2
3
4
5
6
7package com.test;
public class UserFactory {
public static UserService getService() {
return new UserService();
}
}在UserServlet中调用工厂的静态类:
1
2
3
4
5
6
7
8package com.test;
public class UserServlet {
public void addUser() {
UserService user = UserFactory.getService();
user.add();
}
}这样在servlet与factory也存在耦合度。
IOC配置文件的实现xml
1
2<!-- xml文件中配置bean -->
<bean id="userService" class="test.UserService"/>配置完成bean之后:
1
2
3
4
5
6
7
8
9
10
11
12package com.test;
public class UserFactory {
public static UserService getService() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
// 利用dom4j解析xml可以获得id与class
String className = "读取到的class的值";
// 利用反射创建对象
Class clazz = Class.forName(className);
UserService userService = (UserService) clazz.newInstance();
return userService;
}
}但是这样也不算是彻底解耦合,xml文件也需要不断改动,于是注解形式就出现了。
IOC注解配置
比如我们有一个类:
1
2
3
4
5package com.rudy.bean;
public class Color {
}想把他加入到bean中可以这样配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package com.rudy.conf;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import com.rudy.bean.Color;
(Color.class)
public class AppConfig {
/*@Bean("Color")
public Color color() {
return new Color();
}*/
}去掉@Import(Color.class)把下面注释打开也是一样,测试一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18package com.rudy.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.rudy.conf.AppConfig;
public class IOCTest {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfig2.class);
public void test() {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
String[] beanDefinitionNames = annotationConfigApplicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
}
}输出结果:
1
2
3
4
5
6
7
8org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
appConfig
com.rudy.bean.Color也可以根据条件是否加载bean:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22package com.rudy.conf;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import com.rudy.bean.Color;
import com.rudy.condition.MyColor;
public class AppConfig {
/**
* 根据条件自定义加载bean
* @return
*/
(MyColor.class)
public Color color() {
return new Color();
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14package com.rudy.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class MyColor implements Condition{
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return false;
}
}查看测试运行结果:
1
2
3
4
5
6
7org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
appConfig可以发现color没有被放入bean,因为我们自定义的condition返回了false。
condition中可以获取很多信息来进行判断:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//1、获取IOC的beanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2、得到类加载器
ClassLoader classLoader = context.getClassLoader();
//3、获取bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
//4、获取运行的环境
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
if (property.contains("linux")) {
return true;
}
return false;
}
如果是多个路径多个类加入bean可以利用各种注解加上扫描还有自定义规则等等。
比如@Controller,@Service等
1 | package com.rudy.controller; |
1 | package com.rudy.service; |
1 | package com.rudy.conf; |
运行测试类结果如下:
1 | org.springframework.context.annotation.internalConfigurationAnnotationProcessor |
还可以自定义扫描规则
1 | package com.rudy.conf; |
1 | package com.rudy.filter; |
注解的好处可以看到,很多时候我们并不需要知道类的信息,只需要加上注解,然后通过配置文件自定义就可以加载对应的类到bean容器中。
- 最后放一张bean加载解析过程图片
查看评论