Spring的底层核心是IOC和AOP,本文讲解IOC的两种注入案例,让我们一文掌握全部核心知识!
IOC,英文全称Inversion of Control,意思是反转控制,原先new一对象是手工操作,现在交给spring容器,在大规模项目中减少人工代码,做到解耦、高效的目的!
案例:DI操作(xml驱动)
在之前HelloWorld项目上做个简单扩展,进行DI(Dependency Injection)操作的案例:
这里做了一个最精简的演示,通过演示可以看到,如果有多类适配器(子类),只需要修改配置文件,就完成了装配改装,而没有修改java代码! 这就是spring解耦的魅力!
1、准备demo程序
// 这里准备了一个接口,2个实现类,实现不同语种的欢迎词反馈,用于测试代码的调用时不需要修改一行代码,仅需修改配置文件完成功能的切换! public interface UserService { public String sayHello(); } public class UserServiceImpl1 implements UserService { public String sayHello() { return "Nice to meet you!"; } } public class UserServiceImpl2 implements UserService { public String sayHello() { return "你好啊"; } }
2、修改配置文件
<bean class="com.iyyxx.HelloWorld" id="helloWorld"> <property name="userService" ref="userServiceImpl2"/> <!-- ref这里可以替换为userServiceImpl1或userServiceImpl2查看效果 --> </bean> <bean class="com.iyyxx.service.impl.UserServiceImpl1" id="userServiceImpl1"/> <bean class="com.iyyxx.service.impl.UserServiceImpl2" id="userServiceImpl2"/>
3、编写测试代码
public class HelloWorld { private UserService userService; public void setUserService(UserService userService) { this.userService = userService; } public String say2(){ return userService.sayHello(); } public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); HelloWorld helloWorld = (HelloWorld) applicationContext.getBean(HelloWorld.class); System.out.println(helloWorld.say2()); } }
DI的魅力就在于不修改一行java代码,对配置文件进行简单修改就完成了重新装配!
遍历!基于xml的DI注入方式
1、xml配置(这里演示的是set方法的三种注入方式,还可以通过构造函数,还有复杂类型list、set、map等)
<!-- 1、Bean的定义,核心属性class、id --> <bean class="com.iyyxx.service.impl.UserServiceImpl1" id="userServiceImpl1"/> <!-- 2、Bean的手工赋值,在set接口采用value入口 --> <bean class="com.iyyxx.dao.impl.StudentDaoImpl" id="studentDao"> <properties name="userName" value="张三" /> </bean> <!-- 3、Bean的手工赋值,在构造函数接口采用constructor-arg入口 --> <bean class="com.iyyxx.dao.impl.StudentDaoImpl" id="studentDao"> <constructor-arg name="userName" value="张三"/> <constructor-arg name="userAge" value="15"/> </bean> <!-- 4、Bean的引用传递,采用ref入口 --> <bean class="com.iyyxx.dao.impl.StudentDaoImpl" id="studentDao"> <properties name="userService" ref="userServiceImpl1" /> <!-- 这里ref指向其他被管理Bean,可以是id或class --> </bean> <!-- 5、配置文件读取,常见jdbc连接信息尾部设定、spring引用的方式,组合式操作,用${xx.xx}方式进行set或构造函数注入 --> <bean class="com.iyyxx.dao.impl.StudentDaoImpl" id="studentDao"> <properties name="password" ref="${xx.yy.zz}" /> </bean> <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> <!--读取properties文件--> <!-- 6、集合的注入方式 --> <bean class="com.iyyxx.dao.impl.StudentDaoImpl" id="studentDao"> <properties name="list"> <list> <value>xxx</value> <value>yyy</value> </list> </properties> <properties name="set"> <set> <value>xxx</value> <value>yyy</value> </set> </properties> <properties name="aryyay"> <array> <value>xxx</value> <value>yyy</value> </array> </properties> <properties name="properties"> <props> <prop key="k1">v1</prop> <prop key="k2">v2</prop> </props> </properties> <properties name="map"> <map> <entry key="k1" value-ref="phone"/> <entry key="k2" value-ref="phone"/> </map> </properties> </bean>
遍历!基于注解的DI注入方式
注解驱动的di注入有两个注解可以使用
- @Autowired,可作用于
- 成员变量(常用)
- 构造函数(官方Spring4推荐,但臃肿不易阅读)
- 方法上,比较诡异
- @Value,常用于配置文件读取
前置要求:容器配置类已做了包扫描或手工声明,所需bean均已容器化管理,实例如下:
@Configuration public class SpringConfig { @Bean public HelloWorld helloWorld(){ return new HelloWorld(); } @Bean public UserService userService(){ return new UserServiceImpl1(); } } //方案2,比较常用,需要配置器开启@ComponentScan,所有的bean也有Bean声明标签,如@Component、@Service、@Controller @ComponentScan(basePackages = "com.iyyxx") public class SpringConfig { } @Component public class HelloWorld { } @Service public class UserServiceImpl1 implements UserService { }
使用介绍:有了上面的铺垫,使用是很丝滑的,仅仅只是用上@Autowired,除非有多个实现类则需使用==@Qulifier进行特殊指定==
@Component public class HelloWorld { @Autowired @Qualifier("userServiceImpl2") //这里有2个实现类,所以用类型的驼峰命名法可以快速指定,当然也可以在bean上面指定别名! private UserService userService; public String say(){ return "Hello Spring by Annotation"; } public String say2(){ return userService.sayHello(); } public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class); HelloWorld helloWorld = (HelloWorld) applicationContext.getBean(HelloWorld.class); System.out.println(helloWorld.say()); System.out.println(helloWorld.say2()); } }
这里补充下基于构造器、方法的注入方式
//构造器注入方式 @Component public class HelloWorld { private UserService userService; @Autowired public HelloWorld(@Qualifier("userServiceImpl2") UserService userService) { this.userService = userService; } public String say2(){ return userService.sayHello(); } public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class); HelloWorld helloWorld = (HelloWorld) applicationContext.getBean(HelloWorld.class); System.out.println(helloWorld.say2()); } } //方法注入方式 @Component public class HelloWorld { private UserService userService; @Autowired public void setUserService(@Qualifier("userServiceImpl2") UserService userService) { this.userService = userService; } public String say2(){ return userService.sayHello(); } public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class); HelloWorld helloWorld = (HelloWorld) applicationContext.getBean(HelloWorld.class); System.out.println(helloWorld.say2()); } }
注解驱动方式下获取properties文件属性有两点:
- 类上面使用@PropertySource并指定文件名(如果有多级路径就加路径)
- 类中使用成员变量+@Value标签,并使用
${xx.xx}
方式获取配置信息
实例如下:
@Service @PropertySource("jdbc.properties") public class UserServiceImpl2 implements UserService { @Value("${jdbc.username}") private String userName; public String sayHello() { return "你好啊 "+userName; } }
结语
Spring 学习因三种DI的编码方式让学习起来特别辛苦,虽说目前已面向纯注解的开发方式,但依旧存在一些历史项目、复杂架构需要接收,多学点总是没错的,是不是还不过瘾,后面还有一系列的【一文讲解透】系列分享给大家!