Spring注解模式
自动装配
说明
- Spring基于配置文件 为了让属性(对象的引用)注入更加的简单,则推出了自动装配模式
- 根据名称自动装配
- 根据类型自动装配
配置规则
<!--构建Service
自动装配:程序无需手动的编辑property属性
autowire="byName" 根据属性的名称进行注入
1.找到对象的所有的set() setUserDao()
2.setUserDao ~~~ set去掉 ~~~ UserDao ~~~ 首字母小写 ~~~ userDao属性
3.Spring会根据对象的属性查找自己维护的Map集合,根据据userDao的名称,查找Map中的Key与之对应,如果匹配成功,则能自动的效用set()实现注入(必须得有set())
autowire="byType" 根据属性的类型进行注入
1.找到对象的所有的set() setUserDao()
2.根据set(),找到方法中的参数类型UserDao.class
3.Spring根据自己维护的对象的Class进行匹配,如果匹配成功,则实现注入(set())
autowire:规则 如果配置了byName则首先按照name查找,如果查找不到按照byType方式查找
未来,一般首选类型的方式查找-->
<bean id="userController" class="cn.lz.controller.UserController" autowire="byName"></bean>
<bean id="userService" class="cn.lz.service.UserServiceImpl" autowire="byType"></bean>
注解模式
-
关于注解的说明:Spring为了简化xml配置方式,研发注解模式。Spring为了程序更加严谨,通过不同的注解标识不同的层级,但是注解的功能相同。
- @Controller:用来标识Controller层的代码,相当于将对象交给Spring管理
- @Service:用来表示Service层的代码,相当于将对象交给Spring管理
- @Repository:用来标识持久层
- @Component:万用注解
-
注解使用的原理
/** * <bean id="类名首字母小写" class="UserDaoImpl.class"> * 如果需要修改 bean 的 id,则需要手动添加即可 * 即 @Repository(value = "userDao") */ @Repository public class UserDaoImpl implements UserDao { public void addUser(User user) { System.out.println("连接数据库添加用户:" + user); } }
-
编辑配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" 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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--构建User对象--> <bean id="user" class="cn.lz.pojo.User"> <!--根据name的属性查找对象的setId() 将value当作参数 调用set()完成赋值--> <property name="id" value="100"></property> <property name="name"> <value><![CDATA[<武则天>]]></value> </property> </bean> <!--让注解生效,开启包扫描 包路径特点:给定包路径,则自动扫描同包及子孙包中的类 base-package:根据指定的包路径查找注解 写方式:多个包路径 使用逗号(,)分隔 <context:component-scan base-package="cn.lz.controller,cn.lz.service,cn.lz.dao"></context:component-scan> --> <context:component-scan base-package="cn.lz"></context:component-scan> </beans>
-
属性注解
/** * 关于注解的说明 * @Autowired 可以根据类型/属性名称进行注入 首先按照类型进行注入,如果类型注入失败,则根据属性名称注入。 * @Qualifier 如果需要按照名称进行注入,则需要额外添加@Qualifier * @Resource (type = "Xxx.class",name = "属性名称") * 关于注解补充:由于@Resource注解时由Java原生提供的,不是Spring官方的,所以不建议使用 */
- 上述的属性的注入在调用是,自动的封装了set(),所以set()可以省略不写
实现MVC的纯注解开发
编辑xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--开启包扫描-->
<context:component-scan base-package="cn.lz"></context:component-scan>
</beans>
关于注解的说明
-
注解的作用:程序中某些功能以低耦合的形式进行调用。
-
元注解:
- @Target({ElementType.TYPE}) 表示注解对谁有效 type:类,method:方法有效
- @Retention(RetentionPolicy.RUNTIME) 运行期有效
- @Documented 该注解注释编译到API文档中
-
由谁加载:由Spring内部的源码负责调用。
优化xml配置文件
-
说明:随着软件技术发展,xml配置文件显得臃肿,不便于操作,所以Spring后期提出了配置类的思想,将所有的配置文件中的内容写到Java类中。
-
编辑配置类:
@Configuration // 标识我是一个配置类 相当于application.xml //设定包扫描的路径 //@ComponentScan(value = "cn.lz") @ComponentScan("cn.lz") // 如果注解中只有value属性,value可以省略不写 public class SpringConfig { }
-
编辑测试代码:
@Test public void testAnno(){ ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); UserController userController = context.getBean(UserController.class); userController.addUser(); }
Spring中常见的问题
- 接口多实现类情况说明
- 原则:Spring规定一个接口最好只有一个实现类
- 业务需求:要求给UserService提供2个实现类
- 案例分析:
-
编辑实现类A
@Service("userService") public class UserServiceImpl implements UserService { @Autowired //根据类型注入 // @Qualifier //必须按照名称进行匹配 一般不写 private UserDao userDao; public void addUser(User user) { userDao.addUser(user); } }
-
编辑实现类B
@Service("userServiceB") public class UserServiceImplB implements UserService { @Autowired private UserDao userDao; public void addUser(User user) { System.out.println("实现类2完成业务调用"); userDao.addUser(user); } }
-
实现类型的注入
@Controller public class UserController { /** * @Autowired * 首先根据属性的类型注入 * 如果类型不匹配,则根据属性的名称进行注入 * 如果添加了@Qualifier * 则根据属性的名称注入 * 如果名称注入失败,则报错返回 */ @Autowired //自身携带了set() @Qualifier("userServiceB") private UserService userService; public void addUser(){ User user = new User(); user.setId(101); user.setUserName("不知火舞"); userService.addUser(user); } }
-
Spring注解模式执行的过程
- 当程序启动Spring容器时 ApplicationContext 利用beanFactory实例化对象。
- 根据配置类中的包扫描开始加载指定的注解(4个),根据配置文件的顺序依次进行加载。
- 当程序实例化Controller时,由于确实Service对象,所以挂起线程,继续执行后续逻辑;当构建Service时,由于缺少Dao对象,所以挂起线程,继续执行后续逻辑;当实例化Dao成功时,保存到Spring所维护的Map集合中,执行之前挂起的线程;所以以此类推,所有对象实现封装,最终容器启动成功。
- 根据指定的注解注入指定的对象,之后统一交给Spring容器的管理,最终程序启动成功。
Spring容器管理业务数据@Bean注解
-
@Bean作用:通过该注解可以将业务数据实例化之后,交给Spring容器管理,但是@Bean注解应该写到配置类中。
@Configuration // 标识我是一个配置类 相当于application.xml //设定包扫描的路径 //@ComponentScan(value = "cn.lz") // 如果注解中只有value属性 可以省略不写 @ComponentScan("cn.lz") public class SpringConfig { /** * Spring<bean id="方法的名称" class="返回值的类型" /> * 执行@Bean方法,将方法名称当作id,把返回值的对象直接保存到Map集合中 */ @Bean public User user(){ User user = new User(); user.setId(111); user.setUserName("Spring容器"); return user; } }
-
编辑UserController
@Controller public class UserController { @Autowired //自身携带了set() @Qualifier("userServiceB") private UserService userService; @Autowired private User user; //从容器中动态获取 public void addUser(){ userService.addUser(user); } }
Spring动态获取外部数据
-
编辑properties文件
# 规则:properties文件 # 数据结构类型:k-v结构 # 存储数据类型:只能保存String类型 # 加载时的编码格式:加载时默认采用ISO-8859-1格式解析 中文必然乱码 user.id = 1001 # Spring容器获取的当前计算机的名称 慎用 # user.user=Xxx user.userName=鲁班七号
-
编辑配置类
- @PropertySource
- 注解用法:@PropertySource(“classpath:/user.properties”)
- 注解说明:@PropertySource() 作用:加载指定的properties配置文件,将数据保存到容器中
- @Value
- 注解用法:@Value(123) 将123的值赋值给id
- 注解说明:@Value(" u s e r . i d " ) 在 S p r i n g 的容器中查找 k e y = u s e r . i d 的数据,通过 {user.id}") 在Spring的容器中查找key=user.id的数据,通过 user.id")在Spring的容器中查找key=user.id的数据,通过{}语法获取
-
@Configuration // 标识我是一个配置类 相当于application.xml //设定包扫描的路径 //@ComponentScan(value = "cn.lz") // 如果注解中只有value属性 可以省略不写 @ComponentScan("cn.lz") // @PropertySource() 作用:加载指定的properties配置文件,将数据保存到容器中 // encoding = "utf-8" 指定字符集的编码格式 @PropertySource(value = "classpath:/user.properties",encoding = "utf-8") public class SpringConfig { // 定义对象属性,准备接受数据 // @Value(123) 将123的值赋值给id // @Value("${user.id}") 在Spring的容器中查找key=user.id的数据,通过${} 进行触发 @Value("${user.id}") private Integer id; @Value("${user.userName}") private String userName; /** * Spring<bean id="方法的名称" class="返回值的类型" /> * 执行@Bean方法,将方法名称当作id,把返回值的对象直接保存到Map集合中 */ @Bean public User user(){ User user = new User(); user.setId(id); user.setUserName(userName); return user; } }
- @PropertySource