Spring的IOC极大的方便了我们的编程,当我们需要某个对象的时候,不在需要自己去new,只要告诉Spring一声,Spring就会把我们所需要的类准备好,就像你原来出门要穿外套时,你得先跑到衣柜前取出衣服,然后自己穿上。现在好了,你结婚了,只要跟你的另一半说一声,她就会心领神会,把衣服给你拿过来,然后帮你穿上,是不是感觉很爽?Spring有三种配置方法,这三种配置方式如何选择?先看一下这三种配置方式
applicationContext.xml
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="knight" class="com.st.BraveKnight"> <constructor-arg ref="weapon"/> </bean> <bean id="weapon" class="com.st.Weapon"> <property name="type" value="knife"/> </bean> </beans>
BraveKnight
public class BraveKnight { private Weapon weapon; public BraveKnight(Weapon weapon) { this.weapon = weapon; } public Weapon getWeapon() { return weapon; } }
Weapon
public class Weapon { private String type; public String getType() { return type; } public void setType(String type) { this.type = type; } }
public class Main { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); BraveKnight knight = context.getBean(BraveKnight.class); // knife System.out.println(knight.getWeapon().getType()); context.close(); } }
这样一个Spring项目就完成了,可以用spring的test模块,进行测试
@RunWith(SpringJUnit4ClassRunner.class) // 多个文件时可用locations = {"", ""} @ContextConfiguration(locations = "classpath*:/applicationContext.xml") public class XMLTest { @Autowired BraveKnight braveKnight; @Test public void test() { // knife System.out.println(braveKnight.getWeapon().getType()); } }
用XML形式可以在配置文件中,配置我们自己写的类和外部库的类,Spring通过反射可以把这些类都创建出来,并由Spring管理,在你需要的时候给你
BraveKnight
@Component public class BraveKnight { @Autowired private Weapon weapon; public Weapon getWeapon() { return weapon; } }
Weapon
@Component public class Weapon { @Value("knife") // 这个值可以从外部配置文件中通过@Value注解读取到 private String type; public String getType() { return type; } public void setType(String type) { this.type = type; } }
MyConfig
@Configuration // 如果不配置扫描的路径,默认扫描配置类所在的包及其子包下面的所有类 @ComponentScan public class MyConfig { }
public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(MyConfig.class); context.refresh(); BraveKnight knight = context.getBean(BraveKnight.class); // knife System.out.println(knight.getWeapon().getType()); context.close(); } }
@RunWith(SpringJUnit4ClassRunner.class) // 从类中读取配置 @ContextConfiguration(classes = MyConfig.class) public class AnnotaionTest { @Autowired BraveKnight braveKnight; @Test public void test() { // knife System.out.println(braveKnight.getWeapon().getType()); } }
在我们自己的类上,我们可以加@Component注解让Spring来管理,如果是第三方jar包的类呢?它的类上并不会加@Component啊,如果不想用XML来生成第三方jar包的类,JavaConfig在这个时候就派上用场了,接着上面的例子,假如Weapon这个类是第三方jar包的类,则可以通过如下形式让Spring管理
@Configuration // 如果不配置扫描的路径,默认扫描配置类所在的包及其子包下面的所有类 // 可以通过属性basePackages = {""}指定扫描的包 @ComponentScan() public class MyConfig { // name属性默认是方法名,自己可以指定 @Bean(name = "weapon") public Weapon weapon() { Weapon weapon = new Weapon(); weapon.setType("knife"); return weapon; } }
说一个我在用Spring集成Storm遇到的一个有意思的问题,一般想让外部库的类让Spring管理的方法,只要用XML或者JavaConfig配置即可,我项目中有一个ClassA需要继承Storm中的一个ClassB,但是ClassB是一个抽象类,不能在XML中配置,也不能在JavaConfig中创建出来,直接在ClassA上加上@Component注解,并不能让Spring管理ClassA,因为ClassB Spring管理不到,Spring不能管理ClassA,这样就会导致ClassC注入失败
@Component public class ClassA extends ClassB { @Autowired ClassC classC; }
可能会有人想,直接new出来不就行了,奈何ClassC是如下形式
@Component public class ClassC{ @Autowired ClassD classD; }
直接new出来,ClassD就不会被Spring注入进去,怎么办?回头看在启动类,这个类也没有被Spring管理,是怎么取到对象的?是从context中通过getBean方法拿的,但是在其他的类中怎么获取到context,其实Spring提供了一系列Aware接口,只要实现这些接口,就能获取到要东西,我们只要实现ApplicationContextAware接口,就可以获取到context,为了方便我直接封装了一个工具类,通过
SpringHellper.get(ClassC.class)
即可获取Spring管理的ClassC,并能在ClassA中愉快的使用了
@Component public class SpringHelper implements ApplicationContextAware { private static ApplicationContext context; public static ApplicationContext getApplicationContext() { return context; } public static <T> T getBean(Class<T> requiredType) { return context.getBean(requiredType); } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { context = applicationContext; } }
注意要加上Component注解,这样在Spring启动后这个类的context属性就被填充进来了
[1]https://zhuanlan.zhihu.com/p/29938139 [2]https://www.cnblogs.com/hedongfei/p/7899775.html