在没有spring依赖注入的类里面调用spring注解的service等
- 格式:doc
- 大小:31.00 KB
- 文档页数:3
bean service 的几种注入方法Bean是Spring框架中的一个重要概念,它是指由Spring容器管理的对象。
在Spring中,可以通过多种方式将Bean注入到Service中,以提供各种依赖关系的管理和控制。
本文将介绍几种常见的Bean Service注入方法。
一、构造器注入构造器注入是最常见的一种注入方式,它通过在Service类的构造方法中声明参数,来实现对依赖对象的注入。
在Spring容器初始化时,会根据构造方法的参数类型和名称,自动查找并注入对应的Bean对象。
例如:```javapublic class UserService {private UserDao userDao;public UserService(UserDao userDao) {erDao = userDao;}}```在上述代码中,UserService的构造方法接受一个UserDao类型的参数,并将其赋值给成员变量userDao。
这样,在创建UserService对象时,Spring容器会自动查找并注入一个UserDao 对象。
二、属性注入属性注入是另一种常见的注入方式,它通过在Service类的成员变量上使用注解或配置文件的方式,来实现对依赖对象的注入。
在Spring容器初始化时,会自动将配置的Bean对象注入到对应的属性中。
例如:```javapublic class UserService {@Autowiredprivate UserDao userDao;}```在上述代码中,使用@Autowired注解将UserDao对象注入到UserService的成员变量userDao中。
这样,在创建UserService 对象时,Spring容器会自动查找并注入一个UserDao对象。
三、方法注入方法注入是一种比较灵活的注入方式,它通过在Service类的方法中声明参数或使用注解的方式,来实现对依赖对象的注入。
单元测试中简单使⽤Mockito解决SpringBean依赖树问题前提本⽂不是针对Mockito的⼊门教学,主要叙述如何简单的使⽤Mockito解决Bean依赖树问题,对于Mockito的学习请找其他的⽂章或者查阅官⽅⽂档基本概念Junit初始化及存在的问题spring应⽤在unit test时,test是独⽴运⾏的,所以需要⾃⾏ init ApplicationContext,启动 Ioc容器。
Junit要求:Test类中涉及的所有Spring bean 注⼊成功才能完成applicationContext初始化,并启动IOC容器,否则⽆法执⾏unit test。
ApplicationContext初始化的两种⽅式1. ⼿动注⼊(使⽤ @Bean或者 @Component 注⼊所需的类)2. 编写@Configuration 类(使⽤@ComponentScan 指定扫描beans)两种初始化⽅式存在的问题⽅式⼀:所需的beans中,⼀个bean少注⼊了就会导致⽆法初始化上下⽂需要注⼊的bean太多时,需要花费⼤量的时间和精⼒,排查缺漏难度⼤⽅式⼆:颗粒度难以把控,随着项⽬规模变⼤之后,可能导致bean导⼊过多,单元测试跑很久才能通过当项⽬规模⼤了之后,bean之间的依赖往往是复杂的,扫描bean的⽅式可能出现⼀些不属于⾃⼰模块的未知问题或者某些中间件在unitTest环境⽆法正常启动,导致⽆法初始化上下⽂什么是依赖树?在开发应⽤时,往往会出现如上图的树型依赖,⽐如 serviceA 调⽤ serviceB,serviceB ⼜调⽤ serviceC 。
然⽽这只是⼀个简单的例⼦。
真正的开发中,往往⼀个 service 会依赖多个 service ,以及多个 dao ,以此来实现业务逻辑。
⽽根据Junit要求,我们必须将树的路径经过的所有节点(bean)都注⼊才能完成spring上下⽂初始化。
这时如果bean之间的依赖耦合过⼤时,就⽆法跳脱出两种初始化⽅式带来的问题。
springIOC中三种依赖注⼊⽅式⼀、Spring IOC(依赖注⼊的三种⽅式):1、Setter⽅法注⼊。
2、构造⽅法注⼊。
使⽤构造⽅法,注⼊bean值。
关键代码:public UserServiceImpl(UserDao dao) {this.dao=dao;}<bean id="service" class="erServiceImpl"><constructor-arg><ref bean="dao"/></constructor-arg></bean>3、P命名空间注⼊。
⼆、Spring IOC(依赖注⼊的五种不同数据类型):1、注⼊直接量(基本数据类型、字符串)2、引⽤其他Bean组件。
(⾯向接⼝编程)ref属性:<bean id="dao" class="erDaoImpl"></bean><bean id="service" class="erServiceImpl"><property name="dao" ref="dao"></property></bean><ref>⼦元素:<bean id="dao" class="erDaoImpl"></bean><bean id="service" class="erServiceImpl"><property name="dao"><ref bean="dao"/></property></bean>p命名空间:xmlns:p="/schema/p"<bean id="dao" class="erDaoImpl"></bean><bean id="service" class="erServiceImpl" p:dao-ref="dao"></bean>3、使⽤内部Bean。
【SpringFramework】Spring⼊门教程(三)使⽤注解配置本⽂主要介绍四个⽅⾯:(1) 注解版本IOC和DI(2) Spring纯注解(3) Spring测试(4) SpringJDBC - Spring对数据库的操作使⽤注解配置Spring⼊门说在前⾯学习基于注解的IoC配置,⼤家脑海⾥⾸先得有⼀个认知,即注解配置和xml配置要实现的功能都是⼀样的,都是要降低模块间的耦合度。
仅仅只是配置的形式不⼀样。
关于实际的开发中到底使⽤xml还是注解,每家公司有着不同的使⽤习惯。
所以这两种配置⽅式我们都需要掌握。
基于注解配置的⽅式也已经逐渐代替xml配置。
所以我们必须要掌握使⽤注解的⽅式配置Spring。
配置步骤注意:如果使⽤Eclipse需要先安装了STS插件,或者使⽤STS开发⼯具创建项⽬。
本⽂使⽤IDEA进⾏演⽰。
1.2.1. 第⼀步:拷贝必备jar包到⼯程的lib⽬录。
注意:在基于注解的配置中,我们还要多拷贝⼀个aop的jar包。
如下图:1.2.2. 第⼆步:在类的根路径下创建⼀个任意名称的xml⽂件(不能是中⽂)注意:基于注解整合时,Spring配置⽂件导⼊约束时需要多导⼊⼀个context命名空间下的约束。
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/context"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans.xsd/schema/context/schema/context/spring-context.xsd"></beans>1.2.3. 第⼆步:创建⼀个服务类创建⼀个测试的服务类,并且加⼊使⽤@Component注解,声明该类允许注⼊到Spring容器package org.cjw.service;import ponent;/*使⽤注解配置时,需要将Spring框架启动就创建对象的类表⽰为组件类表⽰组件类使⽤@Component注解*/@Componentpublic class CustomerService {public void save() {System.out.println("-保存数据-");}}1.2.4. 第四步在spring的配置⽂件加⼊扫描注解<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/context"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans.xsd/schema/context/schema/context/spring-context.xsd"><!-- 声明扫描包及其⼦包的类,如果发现有组件注解的类,就创建对象并加⼊到容器中去 --><context:component-scan base-package="org.cjw" /></beans>1.2.5. 第五步:测试调⽤代码package org.cjw.test;import org.cjw.service.CustomerService;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class CustomerServiceTest {@Testpublic void testSave() {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");CustomerService customerService = context.getBean(CustomerService.class);customerService.save();}}--测试结果,如果可以调⽤服务⽅法,测试成功。
SpringBoot的属性赋值@Value的⽤法说明⽬录今天学习到了SpringBoot 的属性赋值@Value⽤法先总结例⼦@Value的使⽤及注意事项为什么使⽤参数形式前置条件(注意事项)今天学习到了SpringBoot 的属性赋值@Value⽤法先总结@Value(" 张三 "):直接附在属性名上,在Bean初始化时,会赋初始值@Value(" #{ 20 - 2 } "):可以⽤ #{ },⾥⾯可以写表达式,当然也可以直接 @Value(" #{ 18 } ") 或 @Value(" 18 ")@Value(" ${ } "):利⽤ ${ } 可以取出配置⽂件中的值例⼦配置类:@PropertySource(value={"classpath:/person.properties"})@Configurationpublic class MainConfigOfPropertyValues {@Beanpublic Person person() {return new Person();}}@Configuration:告诉 Spring 这是⼀个配置类@PropertySource:关联配置⽂件,使⽤ @PropertySource 指定读取外部配置⽂件,保存到运⾏的环境变量中,然后可以⽤@Value(" ${ } ") 获取环境变量中的值。
Bean :public class Person {/** 使⽤@Value赋值:* 1. 基本数值* 2. 可以写 #{ }* 3. 可以写 ${ },取出配置⽂件{properties}中的值*/@Value("张三")private String name;@Value("#{20-2}")private int age;@Value("${person.nickName}")private String nickName;public String getNickName() {return nickName;}public void setNickName(String nickName) {this.nickName = nickName;}public String getName() {return name;}public void setName(String name) { = name;}public int getAge() {}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Person [name=" + name + ", age=" + age + ", nickName=" + nickName + "]";}public Person(String name, int age, String nickName) {super(); = name;this.age = age;this.nickName = nickName;}public Person() {super();// TODO Auto-generated constructor stub}}配置⽂件:person.nickName=\u5C0F\u4E09这⾥⾯的 \u5C0F\u4E09 表⽰的是“⼩三”⽽配置⽂件的位置:运⾏:public class IOCTest_PropertyValue {//容器创建AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class); //打印容器中Bean的nameprivate void printBeans(AnnotationConfigApplicationContext applicationContext) {String[] definitionName = applicationContext.getBeanDefinitionNames();for(String name : definitionName) {System.out.println(name);}}@Testpublic void test01() {printBeans(applicationContext);System.out.println("-------------------------------------------------------");//获得容器中的PersonPerson person = (Person) applicationContext.getBean("person");System.out.println(person);//获得环境变量中的值ConfigurableEnvironment environment = applicationContext.getEnvironment();String property = environment.getProperty("person.nickName");System.out.println("环境变量:"+property);applicationContext.close();}}@Value的使⽤及注意事项为什么使⽤使⽤@Vlue可以实现对于线上项⽬的⼀些通⽤配置的修改;或者修改项⽬中可能出现变动,但是却⼜有很多地⽅都在使⽤的⼀些参数,这样我们我可直接通过修改配置⽂件⽽不⽤修改代码的⽅式来达到参数的修改的⽬的参数形式yml⽂件(简单的参数)test1:num: 1name: xiaoming获取数据@Value("${test1.num}")private int num;@Value("${}")private String name;(数组||集合)test:array1: aaa,bbb,cccarray2: 111,222,333array3: 11.1,22.2,33.3list1: ddd,eeee,111,333,222,444获取数据//数组@Value("${test.array1:}")private String[] array1;//集合@Value("#{'${test.list1:}'.split(',')}")private List<String> list1;//集合进⼀步做空数据处理@Value("#{'${test.list:}'.empty ? null : '${test.list:}'.split(',')}")private List<String> testList;(Map)test:map1: '{"name": "zhangsan", "sex": "male"}'map2: '{"math": "90", "english": "85"}'获取数据@Value("#{${test.map2}}")private Map<String,String> map1;@Value("#{${test.map2}}")private Map<String,Integer> map2;前置条件(注意事项)想要能够很好的使⽤的使⽤@Value 需要注意⼀些前置条件1. 使⽤正确的注解@Value的使⽤要找对⽬标,我们所使⽤的注解的引⽤时这样的2. yml⽂件的格式如果你使⽤的是yml⽂件的话,需要注意yml⽂件的注意格式问题,基本上参数名之后的冒号之后都要加空格,⼀般情况下,冒号后⾯加了空格,参数名都会变为蓝⾊3. @Value使⽤的环境要求不能作⽤于静态变量(static);不能作⽤于常量(final);不能在⾮注册的类中使⽤(类需要被注册在spring上下⽂中,如⽤@Service,@RestController,@Component等);使⽤这个类时,只能通过依赖注⼊的⽅式,⽤new的⽅式是不会⾃动注⼊这些配置的。
Spring常⽤的⼀些注解说明@Configuration从Spring3.0,@Configuration⽤于定义配置类,可替换xml配置⽂件,被注解的类内部包含有⼀个或多个被@Bean注解的⽅法。
这些⽅法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进⾏扫描,并⽤于构建bean定义。
@Bean@Bean注解⽤于告诉⽅法,产⽣⼀个Bean对象,然后这个Bean对象交给Spring管理。
产⽣这个Bean对象的⽅法Spring只会调⽤⼀次,随后这个Spring将会将这个Bean对象放在⾃⼰的IOC容器中。
SpringIOC 容器管理⼀个或者多个bean,这些bean都需要在@Configuration注解下进⾏创建,在⼀个⽅法上使⽤@Bean注解就表明这个⽅法需要交给Spring进⾏管理。
@Autowired、@Resource@Resource和@Autowired注解都是⽤来实现依赖注⼊的。
只是@AutoWried按by type⾃动注⼊,⽽@Resource默认按byName⾃动注⼊。
♣ @Autowired@Autowired具有强契约特征,其所标注的属性或参数必须是可装配的。
如果没有Bean可以装配到@Autowired所标注的属性或参数中,⾃动装配就会失败,抛出NoSuchBeanDefinitionException.@Autowired可以对类成员变量、⽅法及构造函数进⾏标注,让 spring 完成 bean ⾃动装配的⼯作。
@Autowired 默认是按照类去匹配,配合 @Qualifier 指定按照名称去装配 bean。
♣ @Resource@Resource是JDK提供的注解,有两个重要属性,分别是name和type。
@Resource依赖注⼊时查找bean的规则既不指定name属性,也不指定type属性,则⾃动按byName⽅式进⾏查找。
Mockito⼊门:如何在Spring中Mock部分对象转载前情提要随着分布式应⽤的开发逐渐成为标配,多个微服务团队合作来完成垂直业务的开发成为了⼀种常态。
微服务使得团队可以专注于⾃⼰的业务逻辑,在和下游依赖和上游对接的团队聚焦好接⼝之后,就进⼊正式的开发。
但是,每个团队的开发节奏往往不同,下游依赖所提供的服务有些时候不能在⾃测的时候提供稳定的服务。
不仅是多个团队,单个团队中每个⼈所负责的模块之间也会存在依赖关系,也就同样存在这样的问题。
这时候,就需要先在代码中模拟出依赖的服务,先确保⾃⼰开发的代码中的主流程能够跑通后。
等下游依赖的服务发布后,再去除模拟的服务,⽤真实的服务测⼀遍。
Mock服务可以依赖于⼀些框架来实现,最经典的就是Mockito。
为什么最近专门来研究⼀下Mock对象的⽅法,是因为之前为了Mock下游服务直接修改了源代码中的实现。
举个例⼦,本来应该从下游服务中根据⽤户ID获取⽤户的详情信息,包括⽤户名,⽤户年龄,⽤户性别等。
但是因为⽤户中⼼的服务尚未发布,我直接修改了源代码中的实现中,返回了⼀个虚拟的⽤户信息。
public Interface UserService{UserInfo getUser(String userId);}public Class UserServiceImpl implements UserService() {@Autowiredprivate UserCenter userCenter;@Overridepublic UserInfo getUser(String userId) {//注释了对下游服务的访问//return userCenter.getUser(userId);//创建了虚拟的⽤户信息并返回UserInfo userInfo = new UserInfo();userInfo.setUserName("xxx");...return userInfo;}}紧接着,问题来了。
依赖注⼊(DI)的三种实现⽅式本⽂来探讨⼀下依赖注⼊的三种实现⽅式是哪三种,Spring的⽀持⼜怎么样。
⾸先,依赖注⼊(DI)的实现⽅式有三种:设值注⼊、构造⽅法注⼊、接⼝注⼊,下⾯来看看这三种注⼊⽅式在Spring中的⽀持怎么样。
1、设值注⼊。
①、新建⼀个项⽬②、新建⼀个User类,实现setter、getter⽅法1.package com.bean;2.3.public class User {4.String username;5.String password;6.public String getUsername() {7.return username;8.}9.public void setUsername(String username) {10.ername = username;11.}12.public String getPassword() {13.return password;14.}15.public void setPassword(String password) {16.this.password = password;17.}18.19.}③、新建⼀个接⼝,名字为UserDAO,⾥⾯包含⼀个save⽅法,将信息存⼊数据库1.3.import er;4.5.public interface UserDAO {6.public void save(User user);7.}④、新建⼀个UserDAO的实现类UserDAOImpl,实现save⽅法,模拟数据库存⼊1.package com.dao;2.3.import er;4.5.public class UserDAOImpl implements UserDAO {6.7.@Override8.public void save(User user) {9.// TODO Auto-generated method stub10.System.out.println(user.getUsername()+"被存储");11.}12.13.}⑤、为了不将直接操作数据库的对象UserDAO暴露给⽤户,需添加service层,在数据库操作前后添加业务逻辑。
【SpringFramework】Spring⼊门教程(⼀)控制反转和依赖注⼊参考资料说在前⾯什么样的架构,我们认为是⼀个优秀的架构?判断准则:可维护性好,可扩展性好,性能。
什么叫可扩展性好?答:在不断添加新的代码的同时,可以不修改原有代码,即符合开闭原则。
如何让程序的可维护性好,可扩展性好呢?业界有⼀个公认的标准:⾼内聚,低耦合。
⾼内聚:就是尽量将代码写在与之功能描述⼀致的模块中。
如User表的操作写在UserDAO⾥⾯,不要写在⾮UserDAO的类⾥⾯。
低耦合:就是尽量减少类与类之间的直接关系。
(重点)直接关系:Controller层依赖Service层,在Controller层直接new Service层的类的对象。
Service层依赖Dao层,在Service层直接new Dao层的对象。
Spring框架就是通过IoC/DI(控制反转/依赖注⼊)实现程序的解耦。
从⽽提⾼程序的维护性和扩展性。
Spring概述Spring是什么Spring是⼀个JavaEE轻量级的⼀站式开发框架。
JavaEE: 就是⽤于开发企业级(B/S)应⽤的技术。
轻量级:使⽤最少代码启动框架,然后根据需求选择需要使⽤的模块。
重量级:早期的EJB,开发⼀个HelloWorld程序都需要引⼊EJB的全部模块。
⼀站式:提供了表⽰层,服务层,持久层的所有⽀持。
Spring框架出现的背景世界上第⼀套由Java官⽅Sun公司推出的企业级开发框架EJB瞬间风靡全球,被各⼤公司所应⽤。
Spring之⽗,Rod Jonhson是⼀个⾳乐博⼠,在Sun公司的⼤⼒推⼴下,也成为EJB框架的使⽤者。
在深⼊研究完EJB框架(由Sun主导开发的⼀个JavaEE开发框架),⽆法接受这么⼀个框架被吹成世界第⼀,具体查看他吐槽EJB的书《Expert one on one J2EE design and development》。
其中突出被他吐槽最厉害的⼀个点就EJB的重量级,就是只要使⽤EJB⾥⾯任何⼀个组件。
SpringBoot:Springboot项⽬中调⽤第三⽅jar包中的类时报错--注⼊类的两种⽅式前⾔场景:将⼀些公共的⽅法封装成了⼀个jar包,在其他项⽬中进⾏引⽤的时候报错报错原因:bean没有注⼊,引进来的jar包没有被spring管理,因为类没有被@Service,@Repository等类注解,如果我们想⽤@Autowired 注⼊也会报错⽰例:@Autowiredpublic UserService userService;报错:Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:No qualifying bean of type [erService] found for dependency:expected at least 1 bean which qualifies as autowire candidate for this dependency.Dependency annotations:{@javax.annotation.Resource(shareable=true, lookup=, name=, description=, authenticationType=CONTAINER, type=classng.Object, mappedName=)}解决⽅式(1)创建配置类使⽤@Bean注解进⾏注⼊类。
@Configurationpublic class UserServiceConfig {@BeanUserService getUserService(){UserService userService = new UserService();return userService;}}解决⽅式(2)在启动类加上扫描注解@ComponentScan("/")//⼿动加上@ComponentScan注解并指定那个bean所在的包//@ComponentScan 的作⽤就是根据定义的扫描路径,把符合扫描规则的类装配到spring容器中@ComponentScan(basePackages={"er"})@SpringBootApplicationpublic class UserApplication {public static void main(String[] args){SpringApplication.run(UserApplication .class, args);}}。
在没有spring依赖注入的类里面调用spring注解的service等
1. 问题描述
在一个BO对象里面, 比如描述团品的对象HotelGroup(是不普通类, 没有spring的注解)里
面, 需要调用一个被spring注解的service, 获取一个数据, 比如, 团品下面的酒店列表, 必须
调用service来获取.
2. 矛盾点
用上面提到的HotelGroup指代要调用spring注解的service的类, 用DataService指代被
调用的spring依赖注入注解的service类.
由于HotelGroup用来表达业务对象, 会有很多团品, 所以不应该被注解, 而DataService是
个服务, 应该注解.
spring的体系里面, 想要调用被注解的对象方法, 比如把自己加入到注解体系里面, 这就是普
通玩法不能搞定的原因.
3.解法
关注点, 就是, 对于"如何不加入spring体系, 却能调用spring的体系内的方法"的回答.
解法是, 创建一个注解的类, 这个类里面把DataService给做成static 的成员变量, 这样,
spring体系内部的一个单件对象, 就被搞进了static区里面.
我们在普通类里面调用某个类的static方法是可以简单做到的.
这样我们就可以堂而皇之地在任何类里面调用这个曾经只能加入spring体系才能调用的服务.
4.实例代码
package com.qunar.des.phoenix.util;
import com.qunar.des.phoenix.entity.bo.Hotel;
import com.qunar.des.phoenix.entity.bo.HotelGroup;
import com.qunar.des.phoenix.index.DataService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* 用来在非spring注解的类内部, 调用spring注解的service等代码.
* 目前没有在实际逻辑中调用.
* Created by fangxue.zhang on 2014/7/26
*/
@Service
public final class IndexUtil {
private static final Logger logger =
LoggerFactory.getLogger(IndexUtil.class);
private static DataService dataService;
@Resource
public void setDataService(DataService dataService) {
IndexUtil.dataService = dataService;
}
public static List
List
for (String seq : seqs) {
Hotel hotel = dataService.getHotel(seq);
if (hotel != null) hotels.add(hotel);
else {
logger.warn("null hotel for seq : {}", seq);
}
}
return hotels;
}
public static DataService getDataService() {
return dataService;
}
public static List
List
for (Long teamId : teamIds) {
HotelGroup hotelGroup = dataService.getHotelGroup(teamId);
if (hotelGroup != null) hotelGroups.add(hotelGroup);
else {
logger.warn("null teamfor teamId : {}", teamId);
}
}
return hotelGroups;
}
}