前言
spring ioc注解方式管理容器中的bean本质是通过aop来实现的,aop后面章节会讲述到,这里仅仅有个印象即可。所以就需要aop的相关依赖,不过还记得这个图吗?
当我们项目中引入spring-context的依赖时,自动就会依赖spring-aop了。
XML方式开启包扫描
想要spring容器来管理所有的bean,而且又是批注方式。这时就需要告知spring扫描那些包下的类。
<?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:context="http://www.springframework.org/schema/context"
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
">
<!-- 进行包扫描 -->
<context:component-scan base-package="com.mayuanfei.springioc"/>
</beans>
说明
- 进行包扫描的本质是把有spring注解的类进行实例化,加入的容器中进行管理。
- context:component-scan就是spring进行包扫描的xml标签
- base-package后放要扫描的包路径。如果有多个路径可以中间用逗号分割,不过还是建议输入一个比较等层的包作为扫描路径
- 可以通过注解指定类的实例化对象id。如:@Component("user1")。不指定默认为类名首字母小写如User类,默认情况在Spring容器中对象的id就是user
Spring Ioc 的几个注解
-
@Component 放在类上,用于标记,告诉spring当前类需要由容器实例化bean并放入容器中
该注解有三个子注解
- @Controller 用于实例化controller层bean
- @Service 用于实例化service层bean
- @Repository 用于实例化持久层bean
理论上这几个注解是可以混着使用的,但是非常不推荐。最好是看到这个注解就知道属于程序逻辑的哪一层。如果不确定是哪一层的,就使用@Component注解。
包扫描过滤
<?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:context="http://www.springframework.org/schema/context"
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
">
<!-- 进行包扫描过滤
use-default-filters默认为true,代表使用默认的扫描过滤器
默认的扫描过滤器会识别并包含 @Component @Controller @Service @Repository 四个注解
如果希望使用自己的过滤,把use-default-filters=false
include-filter: 只扫描的注解 一般和use-default-filters="false"配套使用
exclude-filter: 排除掉的注解 一般和use-default-filters="true"也就是默认配套使用
-->
<!-- 只扫描@Controller注解 -->
<context:component-scan base-package="com.mayuanfei.springioc" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 不扫描@Controller注解 -->
<context:component-scan base-package="com.mayuanfei.springioc">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans>
spring中注入的三种姿势
1. 构造注入
/**
* 构造注入。这是非常推荐的一种注入方式。依赖不为空,省去了我们对其检查。如果无该类型的构造参数直接报错。
*/
@Service
@AllArgsConstructor
public class SysUserServcieImpl implements SysUserService {
private final SysUserMapper userMapper;
/**
* 添加用户
*
* @param user 用户对象
*/
public void addUser(SysUser user) {
this.userMapper.insertSysUser(user);
}
}
这里采用了lombok的方式来简化构造方法
2. Setter注入
/**
* Setter注入。感觉代码很臃肿,实际项目中很少人用
*/
@Service
public class SysUserServcieImpl2 implements SysUserService {
private SysUserMapper userMapper;
/**
* 添加用户
*
* @param user 用户对象
*/
public void addUser(SysUser user) {
this.userMapper.insertSysUser(user);
}
@Autowired
public void setUserMapper(SysUserMapper userMapper) {
this.userMapper = userMapper;
}
}
3. field注入(属性注入)
| 注解 | 解释 |
|---|---|
| @Autowired | 根据属性数据类型自动装配 想使用名称装配可以结合@Qualifier注解 |
| @Qualifier | 根据属性名称注入依赖。结合@Autowired使用 |
| @Resource | 如果指定name属性,就只会按照名称进行装配;如果没有指定name属性,首先会以注解的变量名按照名称进行匹配,如果找不到,再以类型进行匹配都找不到,则匹配失败 |
| @Value | 注解可以用来将外部的值动态注入到 Bean 中,在 @Value 注解中,可以使{} 与 #{} ,它们的区别如下:<br />@Value("{}"):可以获取对应属性文件中定义的属性值。 @Value("#{}"):表示 SpEL 表达式通常用来获取 bean 的属性,或者调用 bean 的某个方法。 |
@SuppressWarnings("all")
@Component
public class SysUserManager2 {
@Value("${user.id}")
private String userId;
@Value("${user.name}")
private String userName;
@Value("${user.address}")
private String address;
@Value("${ip}")
private String ip;
@Value("${port}")
private String port;
// 注入系统属性
@Value("#{systemProperties['os.name']}")
private String osName;
// 注入表达式结果
@Value("#{T(java.lang.Math).random()*1000}")
private double randomNum;
// 注入其他bean执行方法的结果
@Value("#{user1.userRandomName}")
private String fromAnotherBean;
public void showUser() {
System.out.println(ip+":"+port);
System.out.println("操作系统:"+osName);
System.out.println("随机数:"+randomNum);
System.out.println("其他bean的方法:"+fromAnotherBean);
SysUser user = new SysUser();
user.setUserId(""+userId);
user.setUserName(userName);
user.setAddress(address);
System.out.println(user);
}
}
完全注解方式
上面的例子中,我们都还是通过ClassPathXmlApplicationContext来读取一个配置文件来实现的。这个唯一的配置文件是不是能够被代替呢?回答是肯定的。
-
java配置类
@ComponentScan("com.mayuanfei.springioc") @PropertySource(value={"classpath:user.properties","classpath:abc.properties"}, encoding="utf-8") public class SpringConfig { } -
测试代码
@Test public void test7() { ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); SysUserManager2 userManager2 = context.getBean(SysUserManager2.class); userManager2.showUser(); }
代码地址
gitee.com/mayuanfei/S… 下的SpringIoc04
记忆印记
- context:component-scan 包扫描
- include-filter,exclude-filter 包过滤
- @Component、@Controller、@Service、@Repository加入spring容器的四大注解
- spring注入的三种姿势,这里强烈推荐构造注入、其次是@Resource注入。
- 完全注解方式可以替换xml配置文件的包扫描。