Spring核心容器的主要组件是Bean工厂(BeanFactory),Bean工厂使用控制反转(IoC)模式来降低程序代码之间的耦合度,并提供了面向切面编程(AOP)的实现。
简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面编程(AOP)的容器框架。
在具体介绍IoC和AOP之前,我们先简要说明下Spring常用注解
1、@Controller
:用于标注控制器层组件
2、@Service
:用于标注业务层组件
3、@Component
: 用于标注这是一个受 Spring 管理的组件,组件引用名称是类名,第一个字母小写。可以使用@Component(“beanID”) 指定组件的名称
4、@Repository
:用于标注数据访问组件,即DAO组件
5、@Bean
:方法级别的注解,主要用在@Configuration和@Component注解的类里,@Bean注解的方法会产生一个Bean对象,该对象由Spring管理并放到IoC容器中。引用名称是方法名,也可以用@Bean(name = “beanID”)指定组件名
6、@Scope("prototype")
:将组件的范围设置为原型的(即多例)。保证每一个请求有一个单独的action来处理,避免action的线程问题。
由于Spring默认是单例的,只会创建一个action对象,每次访问都是同一个对象,容易产生并发问题,数据不安全。
7、@Autowired
:默认按类型进行自动装配。在容器查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入@Autowired标注的变量中。
8、@Resource
:默认按名称进行自动装配,当找不到与名称匹配的Bean时会按类型装配。
@Controller、@Service、@Component、@Repository都是类级别的注解,如果一个方法也想动态装配,就用@Bean。
当我们想按类型进行自动装配时,就用@Autowired;当我们想按名称(beanID)进行自动装配时,就用@Resource;当我们需要根据比如配置信息等来动态装配不同的组件时,可以用getBean(“beanID”)。
IOC(Inversion of Control)控制反转
例如:现有类 A 依赖于类 B
(1) 什么是控制反转呢?
new
的别人[外部]
来创建对象别人[外部]
就反转控制了数据层对象的创建权(2) Spring和IOC之间的关系是什么呢?
别人[外部]
指的就是Spring的IOC容器(3) IOC容器的作用以及内部存放的是什么?
(4) 当IOC容器中创建好service和dao对象后,程序能正确执行么?
像这种在容器中建立对象与对象之间的绑定关系就要用到DI:
DI(Dependency Injection)依赖注入
(1) 什么是依赖注入呢?
new
的别人[外部其实指的就是IOC容器]
来给注入进来(2) IOC容器中哪些bean之间要建立依赖关系呢?
控制 :指的是对象创建(实例化、管理)的权力
反转 :控制权交给外部环境(Spring 框架、IoC 容器)
开发者把需要创建的对象在XML中进行配置,Spring框架读取这个配置文件,根据配置文件的内容来创建对象
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<bean class="com.southwind.ioc.DataConfig" id="config">
<property name="driverName" value="Driver">property>
<property name="url" value="localhost:8080">property>
<property name="username" value="root">
property>
<property name="password" value="root">
property>
bean>
beans>
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
// DataConfig dataConfig = new DataConfig();
// dataConfig.setDriverName("Driver");
//dataConfig.setUrl("localhost:3306/dbname");
// dataConfig.setUsername("root");
// dataConfig.setPassword("root");
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
System.out.println(context.getBean("config"));
}
}
@Configuration
)用一个 Java 类来替代 XML 文件,把在 XML 中配置的内容放到配置类中。
import com.southwind.ioc.DataConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanConfiguration {
@Bean(value = "config")
public DataConfig dataConfig(){
DataConfig dataConfig = new DataConfig();
dataConfig.setDriverName("Driver");
dataConfig.setUrl("localhost:3306/dbname");
dataConfig.setUsername("root");
dataConfig.setPassword("root");
return dataConfig;
}
}
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfiguration.class);
System.out.println(context.getBean("config"));
更简单的方式,不再需要依赖于 XML 或者配置类,而是直接将 bean 的创建交给目标类,在目标类添加注解来创建。
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Data
@Component
public class DataConfig {
@Value("localhost:3306")
private String url;
@Value("Driver")
private String driverName;
@Value("root")
private String username;
@Value("root")
private String password;
}
ApplicationContext context = new AnnotationConfigApplicationContext("com.southwi
nd.ioc");
System.out.println(context.getBean(DataConfig.class));
自动创建对象,完成依赖注入
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Data
@Component
public class GlobalConfig {
@Value("8080")
private String port;
@Value("/")
private String path;
@Autowired
private DataConfig dataConfig;
}
@Autowired 通过类型进行注入,如果需要通过名称取值,通过 @Qualifier 注解完成名称的映射
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Data
@Component
public class GlobalConfig {
@Value("8080")
private String port;
@Value("/")
private String path;
@Autowired
@Qualifier("config")
private DataConfig dataConfig;
}
IoC 的思想就是两方之间不互相依赖,由第三方容器来管理相关资源。这样有什么好处呢?
参考资料:
- 本文中加入的知乎链接
- B站楠哥学Java – 《两小时弄清楚Spring IOC 和 AOP》