IOC (Inversion of Control)是Spring的核心概念之一。它是指控制反转,它改变了程序员的编程习惯,将应用程序的控制权从应用程序代码中转移到IoC容器中,使应用程序变得更加灵活和易于维护。Spring中的IoC容器充当了控制权的中心,通过配置文件或注解,容器将对象实例化、组装和配置,然后将它们提供给应用程序代码使用。
DI:Dependency Injection,中文意思是依赖注入。依赖注入(DI)是实现控制反转的一种方式,它通过容器自动将所需的依赖关系注入到对象中,从而实现对象之间的解耦。在Spring中,依赖注入可以通过XML配置文件或注解方式来实现。
关于XML方式和注解的方式创建和使用java bean,我们一般使用注解的方式,java bean 可以理解为 js 中的对象,类似这样:
package cn.itcast.domain;
public class User {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
作用:解耦
我结合我常用 js 的方式说一下我理解的IOC,在 js 中我们习惯用函数式编程来解耦我们的程序,函数式其实就是让依赖由函数传入,而不是在函数内部获取。其实和IOC一样,IOC也是让依赖从外部获取,这里的注入的依赖 userService
@Autowired
private UserService userService;
其实就是js函数里的形参 function (userService) {}。
本来我们直接用 new 的方式会让 app 和资源是直接依赖的无法消除,而使用 ioc 我们让 app 问工厂要资源,工厂去控制资源的调度。这种控制权发生的转移我们就叫控制反转。
例如,假设我们有一个名为UserService的类,它需要与数据访问对象(DAO)进行交互。如果我们将UserService与DAO紧密耦合在一起,那么每次需要修改数据访问的实现时,就需要修改UserService的实现。而如果我们使用控制反转,则可以将DAO的实现作为一个bean注入到UserService中,这样UserService只需要关注其需要的数据访问操作,而不需要关注具体的DAO实现。
@Service
public class UserService {
@Autowired
private UserDao userDao;
public List<User> getAllUsers() {
return userDao.getAll();
}
public User getUserById(int id) {
return userDao.getUserById(id);
}
// Other methods...
}
在上述代码中,UserService类通过@Autowired注解将UserDao类的实例注入到自身中,从而避免了直接在UserService类中创建UserDao实例。这是控制反转的一个基本例子,它通过将对象的创建和管理交给了Spring容器来降低类之间的耦合度。
一般很少用
注解的概念:和XML文件一样,注解本身并不能执行,注解本身仅仅只是做一个标记,具体的功能是框架检测到注解标记的位置,然后针对这个位置按照注解标记的功能来执行具体操作。
但是追根本源:所有一切的操作都是由Java代码来完成的,XML和注解只是告诉框架中的Java代码如何执行。
使用@Component注解标记普通组件(相当于在 xml 中配置一个 bean,属性
value:指定 bean 的 id。如果不指定 value 属性,默认 bean 的 id 是当前类的类名。首字母小写。)
import org.springframework.stereotype.Component;
@Component
public class CommonComponent {
}
使用@Repository注解标记持久化层组件
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao {
}
使用@Service注解标记业务逻辑组件
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
}
使用@Controller注解标记控制层组件
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
}
我们可以点进去查看源码,我们会发现:@Controller、@Service、@Repository这三个注解只是在@Component注解的基础上起了三个新的名字。对于Spring的IOC容器来说,这三个组件本质上没有什么区别,而他们的的作用主要是来提高代码的可读性。
@Autowired、@Qualifier、@Resource和@Value是Spring框架中常见的注解,它们的区别主要有以下几点:
@Autowired和@Qualifier:这两个注解都是Spring的注解,用于自动装配bean。@Autowired用于自动装配bean,@Qualifier用于指定在存在多个相同类型的bean时,注入哪一个bean。
@Resource:这个注解属于J2EE的注解,用于自动装配bean。默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。使用这个注解,需要在J2EE环境中才能使用。
@Value:这个注解是Spring框架的注解,用于注入基本类型和String类型的值。这个注解有一个value属性,用于指定数据的值。可以使用Spring中的SpEL(也就是Spring的EL表达式)来定义复杂的表达式。这个注解不能用于装配bean,只能用于注入值。
总结起来,这四个注解的作用各不相同,@Autowired和@Qualifier主要用于自动装配bean,@Resource主要用于在J2EE环境中自动装配bean,而@Value主要用于注入基本类型和String类型的值。
在成员变量上使用@Autowired注解来完成自动装配
在controller层装配Service
@Controller
public class UserController {
@Autowired
private UserService userService;
public void add(){
userService.add();
}
}
在这个例子中,我们有两个同类型的SomeService bean,通过@Qualifier注解指定我们想要注入的bean的名称。
@Configuration
public class AppConfig {
@Bean
@Qualifier("someService1")
public SomeService someService1() {
return new SomeService();
}
@Bean
@Qualifier("someService2")
public SomeService someService2() {
return new SomeService();
}
@Autowired
@Qualifier("someService2")
private SomeService someService;
}
@PostConstruct:用于指定初始化方法。
@PreDestroy:用于指定销毁方法。
@ComponentScan
用于指定 spring 在初始化容器时要扫描的包。作用和在 spring 的 xml 配置文件中的:
是一样的。
@Configuration
@ComponentScan("com.itheima")
public class SpringConfiguration {
}
我们已经配置好了要扫描的包,但是数据源和 JdbcTemplate 对象如何从配置文件中移除呢?
@Bean:
该注解只能写在方法上,表明使用此方法创建一个对象,并且放入 spring 容器。
@PropertySource:
用 于 加载 .properties 文件 中的 配置 。 例如 我们 配置 数据 源时 , 可以 把连 接数 据库 的信 息 写 到
properties 配置文件中,就可以使用此注解指定 properties 配置文件的位置。
属性:
value[]:用于指定 properties 文件位置。如果是在类路径下,需要写上 classpath:
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/**
* 创建一个数据源,并存入 spring 容器中
* @return
*/
@Bean(name="dataSource")
public DataSource createDataSource() {}
}
jdbc.properties 文件:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/day44_ee247_spring