目录
一、注解开发
spring轻代码重配置,就导致了配置繁重,影响开发的效率,注解开发代替xml的配置文件,可以简化配置。spring原始注解主要是代替 < Bean>标签的配置。
主要分为基于xml的自动装配和基于注解的自动装配
二、基于xml的自动装配
基于xml的自动装配需要为每一个类需要自动装配的类中设置对应的set方法,否则会装配失败。
2.1 定义Controller,Service,Dao三层进行模拟
UserController
public class UserController {
//自动装配userService
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void saveUser(){
userService.saveUser();
}
}
UserService
public interface UserService {
void saveUser();
}
UserService实现类UserServiceImpl
public class UserServiceImpl implements UserService {
//自动装配userDao
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void saveUser() {
userDao.saveUser();
}
}
UserDao
public interface UserDao {
void saveUser();
}
UserDao实现类UserDaoImpl
public class UserDaoImpl implements UserDao {
@Override
public void saveUser() {
System.out.println("保存成功");
}
}
2.2 xml配置文件
spring-autowire.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
autowire="byType|byName"
byType:根据对象类型装配
byName:根据名称装配
-->
<bean id="userController" class="com.lx.controller.UserController" autowire="byType">
<!-- <property name="userService" ref="userService"></property>-->
</bean>
<bean id="userService" class="com.lx.service.impl.UserServiceImpl" autowire="byName">
<!-- <property name="userDao" ref="userDao"></property>-->
</bean>
<bean id="userDao" class="com.lx.dao.impl.UserDaoImpl"></bean>
</beans>
没有学自动装配之前是通过set注入的形式对属性进行赋值,自动装配只需要设置autowire属性即可。
2.3 测试
测试类
public class AutoWireByXmlTest {
/*
* 自动装配:
根据指定的策略,在I0C 容器中匹配某个bean,自动为bean中的类类型的属性或接口类型的属性赋值
可以通过bean标签中的autowire属性设置自动装配的策略
自动装配的策略:
no,default: 表示不装配,即bean 中的属性不会自动匹配某个bean为属性赋值,此时属性使用默认值
byType:根据要赋值的属性的类型,在I0C 容器中匹配某个bean,为属性赋值
注意:
a>若通过类型没有找到任何一个类型匹配的bean,此时不装配,属性使用默认值
b>若通过类型找到了多个类型匹配的bean,此时会抛出异常: NoUniqueBeanDefinitionException
总结:当使用byType 实现自动装配时,IOC容器中有且只有一个类型匹配的bean 能够为属性赋值
* 3,byName: 将要赋值的属性的属性名作为bean的id在IOC容器中匹配某个bean,为属性赋值
*总结:当类型匹配bean有多个时, 此时可以使用byName实现自动装配
* */
@Test
public void test(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-autowire.xml");
UserController userController = context.getBean(UserController.class);
userController.saveUser();
}
}
三、基于注解的自动装配
基于注解的自动装配不需要设置set方法
3.1 开启组件扫描
<!--启动组件扫描,指定对应扫描的包路径,该包及其子包下所有的类都会被扫描,加载包含指定注解的类-->
<!--
context :exclude- filter:排除扫描
type:设置排除扫描的方式
type= "annotation/assignable"
annotation:根据注解的类型进行排除,expression需要设置排除的注解的全类名
assignable:根据类的类型进行排除,expression需要设置排除的类的全类名
context: include-filter:包含扫描
注意:需要在context: component - scan标签中设置use - default-filters= "false”
use-default-filters="true" (默认) |所设置的包下所有的类都需要扫描,此时可以使用排除扫描
use-default-filters= "false",所设置的包下所有的类都不需要扫描,此时可以使用包含扫描
-->
<context:component-scan base-package="org.lx">
<!-- <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>-->
<!-- <context:exclude-filter type="assignable" expression="org.lx.controller.UserController"/>-->
<!-- <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>-->
</context:component-scan>
</beans>
3.2 IOC相关注解
@Component,@Controller,@Service ,@Repository
上述4个注解都是加到类上的。
他们都可以起到类似bean标签的作用。可以把加了该注解类的对象放入Spring容器中。
实际再使用时选择任意一个都可以。但是后3个注解是语义化注解。
如果是Service类要求使用@Service。
如果是Dao类要求使用@Repository
如果是Controllerl类(SpringMVC中会学习到)要求使用@Controller
如果是其他类可以使用@Component
- @Component:将类标识为普通组件
- @Controller:将类标识为控制层组件
- @Service:将类标识为业务层组件
- @Repository:将类标识为持久层组倒.
通过注解+扫描所配置的bean的id,默认值为类的小驼峰,即类名的首字母为小写的结果
可以通过标识组件的注解的value属性值设置bean的自定义的id
3.3 示例
UserController
@Controller("userController")
public class UserController {
@Autowired
private UserService userService;
public void saveUser(){
userService.saveUser();
}
}
UserService
public interface UserService {
void saveUser();
}
UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public void saveUser() {
userDao.saveUser();
}
}
UserDao
public interface UserDao {
void saveUser();
}
UserDaoImpl
@Repository
public class UserDaoImpl implements UserDao {
@Override
public void saveUser() {
System.out.println("保存成功");
}
}
3.4 测试
public class IOCByAnnotationTest {
@Test
public void test(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-ioc-annotation.xml");
UserController controller = context.getBean("userController",UserController.class);
controller.saveUser();
}
}
3.5 DI相关注解
如果一个bean已经放入Spring容器中了。那么我们可以使用下列注解实现属性注入,让Spring容器帮我们完成属性的赋值。
-
@Autowired
实现自动装配功能的注解,
加在要注入的成员变量上
@Service("userService") @Data @NoArgsConstructor @AllArgsConstructor public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; public void show() { userDao.show(); } }
- @Autowired注解能够标识的位置
- 标识在成员变量上,此时不需要设置成员变量的set方法
- 标识在set方法上
- 标识在为当前成员变量赋值的有参构造上
- @Autowired注解的原理
- 默认通过byType的方式,在IOC 容器中通过类型匹配某个bean为属性赋值
- 若有多个类型匹配的bean,此时会自动转换为byName的方式实现自动装配的效果
即将要赋值的属性的属性名作为bean的id匹配某个bean为属性赋值 - 若byType和byName的方式都无妨实现自动装配,即I0C 容器中有多个类型匹配的bean
且这些bean的id和要赋值的属性的属性名都不一致,此时抛异常: NoUniqueBeanDefinitionException - 此时可以在要赋值的属性上,添加一个注解@Qualifier
通过该注解的value属性值,指定某个bean的id,将这个bean为属性赋值
注意: 若IOC容器中没有任何一个类型匹配的bean, 此时抛出异常: NoSuchBeanDefinitionException
在@Autowired注解中有个属性required,默认值为true,要求必须完成自动装配
可以将required设置为false,此时能装配则装配,无法装配则使用属性的默认值
- @Autowired注解能够标识的位置
-
@Value
主要用于String,Integer等可以直接赋值的属性注入。不依赖setter方法,支持SpEL表达式。
@Service("userService") @Data @NoArgsConstructor @AllArgsConstructor public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Value("199") private int num; @Value("lx") private String str; @Value("#{19+3}") private Integer age; public void show() { userDao.show(); } }
-
@Qualifier
如果相同类型的bean在容器中有多个时,单独使用@AutoWired就不能满足要求,这时候可以再加上@Qualifier来指定bean的名字从容器中获取bean注入。
@Autowired @Qualifier("userDao2") private UserDao userDao;
-
@Resource
相当于@Autowired+ @Qualifier,按照名称进行注入,
加在要注入的成员变量上
@Resource("userDao2")
private UserDao userDao;
四、xml配置文件相关注解
4.1 @Configuration
标注在类上,表示当前类是一个配置类。我们可以用注解类来完全替换掉xml配置文件。
注意:如果使用配置类替换了xml配置,spring容器要使用:AnnotationConfigApplicationContext
例如:
@Configuration
public class ApplicationConfig {
}
4.2 @ComponentScan
可以用来代替context:component-scan标签来配置组件扫描。
basePackages属性来指定要扫描的包。
注意要加在配置类上。
@Configuration
@ComponentScan(basePackages = "com.lx")//指定要扫描的包
public class ApplicationConfig {
}
4.3 @Bean
可以用来代替bean标签,主要用于第三方类的注入。
使用:定义一个方法,在方法中创建对应的对象并且作为返回值返回。然后在方法上加上@Bean注解,注解的value属性来设置bean的名称。
例如:
@Configuration
@ComponentScan(basePackages = "com.lx")
public class ApplicationConfig {
@Bean("dataSource")
public DruidDataSource getDataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
druidDataSource.setUsername("root");
druidDataSource.setUrl("jdbc:mysql://localhost:3306/mybatis_db");
druidDataSource.setPassword("root");
return druidDataSource;
}
}
注意事项:如果同一种类型的对象在容器中只有一个,我们可以不设置bean的名称
获取方式如下:
public static void main(String[] args) {
//创建注解容器
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(ApplicationConfig.class);
//根据对应类的字节码对象获取
DataSource bean = app.getBean(DataSource.class);
System.out.println(userService);
}
4.4 @PropertySource
可以用来代替context:property-placeholder,让Spring读取指定的properties文件。然后可以使用@Value来获取读取到的值。
使用:在配置类上加@PropertySource注解,注解的value属性来设置properties文件的路径。
然后在配置类中定义成员变量。在成员变量上使用@Value注解来获取读到的值并给对应的成员变量赋值。
properties配置文件:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_db
jdbc.username=root
jdbc.password=root
读取文件并且获取值
@Configuration
@ComponentScan(basePackages = "com.lx")
@PropertySource("jdbc.properties")
public class ApplicationConfig {
@Value("${jdbc.driver}")
private String driverClassName;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DruidDataSource getDataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(driverClassName);
druidDataSource.setUsername(username);
druidDataSource.setUrl(url);
druidDataSource.setPassword(password);
return druidDataSource;
}
}
注意事项:使用@Value获取读到的properties文件中的值时使用的是${key},而不是#{key}。