哈喽,大家好,我是Java小面。
Spring的底层核心是IOC和AOP,本文讲解IOC的两种注入案例,让我们一文掌握全部核心知识!
IOC,英文全称Inversion of Control,意思是反转控制,原先new一对象是手工操作,现在交给spring容器,在大规模项目中减少人工代码,做到解耦、高效的目的!
在之前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代码,对配置文件进行简单修改就完成了重新装配!
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注入有两个注解可以使用
前置要求:容器配置类已做了包扫描或手工声明,所需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文件属性有两点:
${xx.xx}方式获取配置信息实例如下:
@Service
@PropertySource("jdbc.properties")
public class UserServiceImpl2 implements UserService {
@Value("${jdbc.username}")
private String userName;
public String sayHello() {
return "你好啊 "+userName;
}
}
Spring 学习因三种DI的编码方式让学习起来特别辛苦,虽说目前已面向纯注解的开发方式,但依旧存在一些历史项目、复杂架构需要接收,多学点总是没错的,是不是还不过瘾,后面还有一系列的【一文讲解透】系列分享给大家!