Java Spring各种依赖注入注解的区别
- 格式:docx
- 大小:48.37 KB
- 文档页数:22
Spring常⽤的三种注⼊⽅式Spring通过DI(依赖注⼊)实现IOC(控制反转),常⽤的注⼊⽅式主要有三种:构造⽅法注⼊,setter注⼊,基于注解的注⼊。
构造⽅法注⼊先简单看⼀下测试项⽬的结构,⽤maven构建的,四个包:entity:存储实体,⾥⾯只有⼀个User类dao:数据访问,⼀个接⼝,两个实现类service:服务层,⼀个接⼝,⼀个实现类,实现类依赖于IUserDaotest:测试包在spring的配置⽂件中注册UserService,将UserDaoJdbc通过constructor-arg标签注⼊到UserService的某个有参数的构造⽅法<!-- 注册userService --><bean id="userService" class="erService"><constructor-arg ref="userDaoJdbc"></constructor-arg></bean><!-- 注册jdbc实现的dao --><bean id="userDaoJdbc" class="erDaoJdbc"></bean>如果只有⼀个有参数的构造⽅法并且参数类型与注⼊的bean的类型匹配,那就会注⼊到该构造⽅法中。
public class UserService implements IUserService {private IUserDao userDao;public UserService(IUserDao userDao) {erDao = userDao;}public void loginUser() {userDao.loginUser();}}@Testpublic void testDI() {ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");// 获取bean对象UserService userService = ac.getBean(UserService.class, "userService");// 模拟⽤户登录userService.loginUser();}测试打印结果:jdbc-登录成功注:模拟⽤户登录的loginUser⽅法其实只是打印了⼀条输出语句,jdbc实现的类输出的是:jdbc-登录成功,mybatis实现的类输出的是:mybatis-登录成功。
Spring的四个基本注解ann...SpringMVC的四个基本注解annotation(控制层,业务层,持久层) -- @Component、@Repository @Service、@Controller SpringMVC中四个基本注解:@Component、@Repository @Service、@Controller看字面含义,很容易却别出其中三个:@Controller控制层,就是我们的action层@Service 业务逻辑层,就是我们的service或者manager 层@Repository持久层,就是我们常说的DAO层而@Component (字面意思就是组件),它在你确定不了事哪一个层的时候使用。
其实,这四个注解的效果都是一样的,Spring都会把它们当做需要注入的Bean加载在上下文中;但是在项目中,却建议你严格按照除Componen的其余三个注解的含义使用在项目中。
这对分层结构的web架构很有好处!!这里讲的是SpringMVC中这四个注解的作用,其实Srping中这四个注解的作用和SpringMVC一样.示例:1. 控制层@Controller // 注释为controller@RequestMapping("/login")public class LoginAction {@Autowired@Qualifier("userService") //注释指定注入 Beanprivate IUserService userService;。
其他略。
}2. 业务逻辑层@Service("userService")public class UserServiceImpl implements IUserService {@Autowired@Qualifier("userDao")private IUserDao userDao;。
Spring 2.5 中除了提供@Component 注释外,还定义了几个拥有特殊语义的注释,它们分别是:@Repository、@Service 和@Controller。
在目前的Spring 版本中,这3 个注释和@Component 是等效的,但是从注释类的命名上,很容易看出这 3 个注释分别和持久层、业务层和控制层(Web 层)相对应。
虽然目前这 3 个注释和@Component 相比没有什么新意,但Spring 将在以后的版本中为它们添加特殊的功能。
所以,如果Web 应用程序采用了经典的三层分层结构的话,最好在持久层、业务层和控制层分别采用@Repository、@Service 和@Controller 对分层中的类进行注释,而用@Component 对那些比较中立的类进行注释。
在一个稍大的项目中,通常会有上百个组件,如果这些组件采用xml的bean定义来配置,显然会增加配置文件的体积,查找以及维护起来也不太方便。
Spring2.5为我们引入了组件自动扫描机制,他可以在类路径底下寻找标注了@Component,@Service,@Controller,@Repository注解的类,并把这些类纳入进spring容器中管理。
它的作用和在xml文件中使用bean节点配置组件时一样的。
要使用自动扫描机制,我们需要打开以下配置信息:Java代码1. <?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-2.5.xsd/schema/context/schema/context/spring-context-2.5.xsd"2. >3.4. <context:component-scan base-package=”com.eric.spring”>5. </beans>6. 其中base-package为需要扫描的包(含所有子包)@Service用于标注业务层组件,@Controller用于标注控制层组件(如struts中的action),@Repository用于标注数据访问组件,即DAO组件,而@Component 泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
spring4——IOC之基于注解的依赖注⼊(DI)spring容器对于Bean的创建和对象属性的依赖注⼊提供了注解的⽀持,让我们在开发中能够更加便捷的实现对象的创建和对象属性的依赖注⼊。
⼀,对于Bean的创建spring容器提供了以下四个注解的⽀持:1、@Component2、@Repository dao层实现类的注解3、@Service service层实现类的注解4、@Controller controller层实现类的注解以上四个注解在普通使⽤中是等效的,但在web项⽬中为了区分三层架构中不同层之间Bean的创建,为了避免注解使⽤的混乱,使⽤后三个注解进⾏区分。
⼆,对于Bean属性的依赖注⼊分为两类,⼀类是对于属性是String类型或者基本数据类型Spring容器提供了@Value这个注解,另⼀类是对于属性是对象的提供了@Autowired和@Resource这两个注解。
其中,@Autowired这个注解是spring框架⾃带的注解,⽽@Resource(javax.annotation.Resource)这个注解是javax扩展包中注解规范的⼀种,⽽spring对这⼀注解提供了⽀持。
下⾯我们通过实验来说明注解对于bean创建和bean属性依赖注⼊的实现。
⾸先要在配置⽂件中配置注解扫描的驱动。
<context:annotation-config/><context:component-scan base-package="com.opensource"/>这⾥提⼀句,如果配置了注解扫描包的范围,也就是第⼆⾏,那么<context:annotation-config/>可以不⽤配置,因为配置扫描包的范围后,注解的驱动也就有了。
实验⼀,bean的创建,因为spring容器对于bean创建的四个注解是等效,这⾥我们使⽤@Component这个注解Student类:@Componentpublic class Student {public Student(){System.out.println("spring容器调⽤Student类的⽆参构造器");}测试类:public class MyTest {public static void main(String[] args) {ApplicationContext ac = new ClassPathXmlApplicationContext("spring-bean.xml");}}实验结果:实验⼆:bean属性为String类型及基本数据类型的的依赖注⼊student类:@Component(value = "student")public class Student {@Value("张三")private String name;@Value("23")private int age;public String getName() {return name;}public int getAge() {return age;}}在这⾥ @Component(value = "student") value指定的是bean的id,另外对于注解⽅式实现的依赖注⼊,bean的属性⽆需再提供setter⽅法。
Spring注解@component、@service、@Autowired等作⽤与区别1、@Service⽤于标注业务层组件2、@Controller⽤于标注控制层组件(如struts中的action)3、@Repository⽤于标注数据访问组件,即DAO组件.4、@Component泛指组件,当组件不好归类的时候,我们可以使⽤这个注解进⾏标注。
5、@Autowired与@Resource的区别: @Autowired由Spring提供,只按照byType注⼊,默认情况下必须要求依赖对象存在,如果要允许null值,可以设置它的required属性为false。
如果想使⽤名称装配可以结合@Qualifier注解进⾏使⽤。
public class UserService {@Autowired@Qualifier(name="userDao1")private UserDao userDao;} @Resource由J2EE提供,默认按照byName⾃动注⼊,Spring将@Resource注解的name属性解析为bean的名字,type属性则解析为bean的类型。
所以如果使⽤name属性,则使⽤byName的⾃动注⼊策略,⽽使⽤type属性则使⽤byType⾃动注⼊策略。
①如果同时指定了name和type,则从Spring上下⽂中找到唯⼀匹配的bean进⾏装配,找不到则抛出异常。
②如果指定了name,则从上下⽂中查找名称(id)匹配的bean进⾏装配,找不到则抛出异常。
③如果指定了type,则从上下⽂中找到类似匹配的唯⼀bean进⾏装配,找不到或是找到多个,都会抛出异常。
④如果既没有指定name,⼜没有指定type,则⾃动按照byName⽅式进⾏装配;如果没有匹配,则回退为⼀个原始类型进⾏匹配,如果匹配则⾃动装配。
总结:@Resource的作⽤相当于@Autowired,只不过@Autowired按byType⾃动注⼊。
s p r i n g四种依赖注入方式The document was finally revised on 2021博客分类:•??平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new 一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依赖类不由程序员实例化,而是通过spring容器帮我们new指定实例并且将实例注入到需要该对象的类中。
依赖注入的另一种说法是“控制反转”,通俗的理解是:平常我们new一个实例,这个实例的控制权是我们程序员,而控制反转是指new实例工作不由我们程序员来做而是交给spring容器来做。
spring有多种依赖注入的形式,下面仅介绍spring通过xml进行IOC配置的方式:•Set注入这是最简单的注入方式,假设有一个SpringAction,类中需要实例化一个SpringDao对象,那么就可以定义一个private的SpringDao成员变量,然后创建SpringDao的set方法(这是ioc的注入入口):Java代码1.package?2.publicclassSpringAction{.>,这样其实是spring将SpringDaoImpl对象实例化并且调用SpringAction 的setSpringDao方法将SpringDao注入:Java代码1.<!--配置bean,配置后该类由spring管理-->?2.<beanname="springAction"class="">?3.4.<!--(1)依赖注入,配置当前类中相应的属性-->5.<propertyname="springDao"6.ref="springDao"></property>?7.8.</bean>9.<beanname="springDao"class=""></bean>?10.11.•构造器注入这种方式的注入是指带有参数的构造函数注入,看下面的例子,我创建了两个成员变量SpringDao和User,但是并未设置对象的set方法,所以就不能支持第一种注入方式,这里的注入方式是在SpringAction 的构造函数中注入,也就是说在创建SpringAction对象时要将SpringDao和User两个参数值传进来:Java代码1.publicclassSpringAction{态方法()"来获取对象,而是依然通过spring注入的形式获取:Java代码1.package?2.3.import?4.import?5.import?6.7.publicclassDaoFactory{1.."class="..."scope="prototype">。
【转】Spring学习笔记1—依赖注⼊(构造器注⼊、set注⼊和注解注⼊)什么是依赖注⼊在以前的java开发中,某个类中需要依赖其它类的⽅法时,通常是new⼀个依赖类再调⽤类实例的⽅法,这种⽅法耦合度太⾼并且不容易测试,spring提出了依赖注⼊的思想,即依赖类不由程序员实例化,⽽是通过spring容器帮我们new指定实例并且将实例注⼊到需要该对象的类中。
依赖注⼊的⽅式依赖注⼊有3种⽅式:构造器注⼊、set注⼊和注解注⼊。
1.构造器注⼊构造器注⼊保证⼀些必要的属性在Bean实例化时就得到设置,并且确保了Bean实例在实例化后就可以使⽤。
使⽤⽅式:1. 在类中,不⽤为属性设置setter⽅法,但是需要⽣成该类带参的构造⽅法。
2. 在配置⽂件中配置该类的bean,并配置构造器,在配置构造器中⽤到了<constructor-arg>节点,该节点有四个属性index:指定注⼊属性的顺序索引,从0开始;type:指该属性所对应的类型;ref:引⽤的依赖对象;value:当注⼊的不是依赖对象,⽽是基本数据类型时,就⽤value;例⼦1:public class SpringAction {//注⼊对象springDaoprivate SpringDao springDao;private User user;public SpringAction(SpringDao springDao,User user){this.springDao = springDao;er = user;System.out.println("构造⽅法调⽤springDao和user");}public void save(){user.setName("卡卡");springDao.save(user);}}<bean name="springAction" class="com.bless.springdemo.action.SpringAction"><!--(2)创建构造器注⼊,如果主类有带参的构造⽅法则需添加此配置--><constructor-arg index="0" ref="springDao"></constructor-arg><constructor-arg index="1" ref="user"></constructor-arg></bean><bean name="springDao" class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean><bean name="user" class="er"></bean>其中index属性表⽰注⼊的bean在构造⽅法中的参数顺序。
论述spring依赖注入中注解分类、作用及应用方式spring依赖注入(DI)是把实例对象放在spring容器中运用注解注入进行实例依赖关系的维护,通常可分为以下几类:一、 Spring注解:1、 @Resource:该注解直接用欧文名字,如 applicationContext.xml 里定义的 bean 的名字作为注解的 value 属性,通过名字装配bean。
2、 @Autowired:该注解根据类型装配bean,如果项目中有多个实现类型的bean 那么需要标注 @Qualifier("beanName") 来指定注入bean为哪一个。
3、 @Value:该注解通过表达式来设置属性值,可以是一个字符串、某个bean 的属性值、某个配置文件的值等,例如@Value("#{systemProperties['']}"),表示从systemProperties取出为属性值4、 @PostConstruct:该注解标注的方法会在bean初始化的时候执行,也可以在配置文件中配置 init-method="methodName",当容器装配完成 bean 的时候会调用methodName 对应的方法5、 @PreDestroy:该注解标注的方法会在bean销毁的时候执行,也可以在配置文件中配置 destroy-method="methodName",当容器销毁 bean 的时候会调用methodName 对应的方法二、 JavaEE注解:1、 @javax.annotation.Resource :该注解可以直接通过它的 property name 属性来指定注入bean 名字2、 @javax.inject.Inject:该注解是JavaEE6 中出现的,和 @Autowired 一样可以根据类型装配bean三、其他的注解:1、 @Repository:该注解用来标注 Dao 层的组件,表明该组件是一个数据访问层的实现2、 @Service:该注解用来标注 Service 层的组件,表明是业务类组件3、 @Controller:该注解用来标注 controller 层的组件,进行请求处理这些注解有一些作用是相同的,比如都可以被spring容器所扫描到,但他们各有特殊用途,且使用方式也各有不同,以上便是spring依赖注入中注解分类、作用及应用方式的详细介绍。
SpringBean常⽤依赖注⼊⽅式详解⼀般⽽⾔,Spring的依赖注⼊有三种:构造器注⼊、setter注⼊以及接⼝注⼊。
本⽂主要讲构造器注⼊与setter注⼊。
1、构造器注⼊为了让Spring完成构造器注⼊,我们需要去描述具体的类、构造⽅法并设置构造⽅法的对应参数。
代码如下:public class Role {private Long id;private String roleName;private String note;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getRoleName() {return roleName;}public void setRoleName(String roleName) {this.roleName = roleName;}public String getNote() {return note;}public void setNote(String note) {this.note = note;}public Role(String roleName, String note) {this.roleName = roleName;this.note = note;}public Role() {}public void run() {System.out.println("roleName:" + roleName + ";" + "note:" + note);}}这个时候是没有办法利⽤⽆参的构造⽅法去创建对象的,为了使Spring能正确创建这个对象,需要在xml⽂件中加⼊如下bean:<bean id="role1" class="com.ssm.chapter.pojo.Role"><constructor-arg index="0" value="总经理" /><constructor-arg index="1" value="公司管理者" /></bean>其中,constructor-arg元素⽤于定义类构造⽅法的参数,index⽤于定义参数的位置,⽽value是设置值,通过这样定义spring 便知道使⽤Role(String, String)这样的构造⽅法去创建对象了。
Java依赖注⼊的三种⽅式Spring通过DI(依赖注⼊)实现IOC(控制反转),常⽤的注⼊⽅式主要有三种:构造⽅法注⼊,setter注⼊,基于注解的注⼊。
构造⽅法注⼊构造器注⼊:保证了⼀些必要的属性在Bean实例化时就设置,并且确保了bean实例在实例化后就可以使⽤.1.在类中,不⽤为属性设置setter⽅法,只需提供构造⽅法即可2.在构造⽂件中配置该类bean,并配置构造器,在配置构造器中⽤//ApplicationContext.xml<bean id="action" class="erAction"><constructor-arg index ="0" name="name" value="Murphy"></constructor-arg></bean>提供构造⽅法public class UserAction {private String name;public UserAction(String name) { = name;}}setter注⼊1.根据property标签的name属性的值去找对应的setter⽅法.例如: name= “aa” 对应的就是setAa⽅法.2.由于属性注⼊具有可选性和灵活性⾼的优点,是实际上最常⽤的注⼊⽅式.3.属性注⼊要求bean提供⼀个默认的构造函数,并为需要注⼊的属性提供对应的setter⽅法.spring先调⽤bean默认的构造函数实例化bean对象,然后通过反射机制的⽅法调⽤setter⽅法注⼊属性值.4.还有⼀点需要注意:如果通过set⽅法注⼊属性,那么spring会通过默认的空参构造⽅法来实例化对象,所以如果在类中写了⼀个带有参数的构造⽅法,⼀定要把空参数的构造⽅法写上,否则spring没有办法实例化对象,导致报错。
Java必须掌握的20+种Spring常⽤注解Spring部分1、声明bean的注解@Component 组件,没有明确的⾓⾊@Service 在业务逻辑层使⽤(service层)@Repository 在数据访问层使⽤(dao层)@Controller 在展现层使⽤,控制器的声明(C)2、注⼊bean的注解@Autowired:由Spring提供@Inject:由JSR-330提供@Resource:由JSR-250提供都可以注解在set⽅法和属性上,推荐注解在属性上(⼀⽬了然,少写代码)。
3、java配置类相关注解@Configuration 声明当前类为配置类,相当于xml形式的Spring配置(类上)@Bean 注解在⽅法上,声明当前⽅法的返回值为⼀个bean,替代xml中的⽅式(⽅法上)@Configuration 声明当前类为配置类,其中内部组合了@Component注解,表明这个类是⼀个bean(类上)@ComponentScan ⽤于对Component进⾏扫描,相当于xml中的(类上)@WishlyConfiguration 为@Configuration与@ComponentScan的组合注解,可以替代这两个注解4、切⾯(AOP)相关注解Spring⽀持AspectJ的注解式切⾯编程。
@Aspect 声明⼀个切⾯(类上)使⽤@After、@Before、@Around定义建⾔(advice),可直接将拦截规则(切点)作为参数。
@After 在⽅法执⾏之后执⾏(⽅法上)@Before 在⽅法执⾏之前执⾏(⽅法上)@Around 在⽅法执⾏之前与之后执⾏(⽅法上)@PointCut 声明切点在java配置类中使⽤@EnableAspectJAutoProxy注解开启Spring对AspectJ代理的⽀持(类上)5、@Bean的属性⽀持@Scope 设置Spring容器如何新建Bean实例(⽅法上,得有@Bean)其设置类型包括:Singleton (单例,⼀个Spring容器中只有⼀个bean实例,默认模式),Protetype (每次调⽤新建⼀个bean),Request (web项⽬中,给每个http request新建⼀个bean),Session (web项⽬中,给每个http session新建⼀个bean),GlobalSession(给每⼀个 global http session新建⼀个Bean实例)@StepScope 在Spring Batch中还有涉及@PostConstruct 由JSR-250提供,在构造函数执⾏完之后执⾏,等价于xml配置⽂件中bean的initMethod@PreDestory 由JSR-250提供,在Bean销毁之前执⾏,等价于xml配置⽂件中bean的destroyMethod6、@Value注解@Value 为属性注⼊值(属性上)⽀持如下⽅式的注⼊:》注⼊普通字符》注⼊操作系统属性》注⼊表达式结果》注⼊其它bean属性》注⼊⽂件资源》注⼊⽹站资源》注⼊配置⽂件注⼊配置使⽤⽅法:①编写配置⽂件(test.properties)=《三体》② @PropertySource 加载配置⽂件(类上)③还需配置⼀个PropertySourcesPlaceholderConfigurer的bean。
Spring依赖注⼊:注解注⼊注解注⼊顾名思义就是通过注解来实现注⼊,Spring和注⼊相关的常见注解有Autowired、Resource、Qualifier、Service、Controller、Repository、Component。
1.@Autowired是⾃动注⼊,⾃动从spring的上下⽂找到合适的bean来注⼊@Autowired(required=true)表⽰必须找到匹配的Bean,否则将报异常。
@Autowired默认按类型匹配注⼊Bean在Spring中,@Autowired注⼊的类型可以是接⼝⽐如,在Service层中注⼊Dao,如下⽰:@Autowiredprivate UserDao userDao;2.@Resource要求提供⼀个Bean名称的属性,如果属性为空,⾃动采⽤标注处的变量名和⽅法名作为Bean的名称。
@Resource默认按名称匹配注⼊Bean⽐如,在Controller层中注⼊Service,名称为Service的实现类,如下⽰@Resource(name = "userServiceImpl")private UserService userService;另外要注意,@Resource是java⾃带的注解,不是Spring中的注解。
@Resource注解完整的包路径为import javax.annotation.Resource;3.@Qualifier 指定注⼊bean的名称⽐如,在Controller层中注⼊Service,名称为Service的实现类,如下⽰@Autowired@Qualifier("userServiceImp")private UserSerevice userService;4.@Service,@Controller,@Repository分别标记类是Service层,Controller层,Dao层的类,spring扫描注解配置时,会标记这些类要⽣成bean。
java 依赖注入详解Java的依赖注入(Dependency Injection,简称DI)是一种软件设计模式,用于管理对象之间的依赖关系。
它通过将依赖关系从代码中移除,实现对象之间的松耦合。
本文将详细解释Java的依赖注入,并介绍其原理、用法以及优缺点。
一、依赖注入的原理和概念依赖注入的原理就是通过外部容器来管理对象之间的依赖关系,而不是在代码中显式地创建和管理这些依赖关系。
典型的依赖注入的实现方式是通过构造函数、Setter方法或接口来注入依赖。
1.构造函数注入:在对象创建时,通过构造函数传递依赖关系。
2. Setter方法注入:通过Setter方法设置依赖关系。
3.接口注入:通过接口来定义依赖关系,在实现类中注入依赖。
二、依赖注入的优点1.降低代码的耦合性:依赖注入将对象之间的关系交给外部容器管理,代码只需要关注自身的功能,这样能够降低代码的耦合性,提高代码的可维护性和可测试性。
2.提高代码的可扩展性:依赖注入可以轻松地替换依赖关系,通过切换不同的实现类,可以实现对代码的灵活扩展。
3.简化对象的创建和管理:依赖注入由外部容器来负责对象的创建和管理,避免了重复的代码。
4.提高代码的可读性:依赖注入能够将对象之间的依赖关系从代码中解耦出来,使得代码更加清晰易读。
三、依赖注入的实现方式1.使用框架:许多Java框架(如Spring)提供了依赖注入的支持。
通过在配置文件中定义对象的依赖关系,框架会在运行时自动注入依赖。
2.使用注解:Java可以通过注解来实现依赖注入。
通过在字段或Setter方法上添加注解,容器会根据注解信息来自动注入依赖。
3.手动管理:在没有使用框架或注解的情况下,可以手动管理对象之间的依赖关系。
可以通过构造函数、Setter方法或接口来进行依赖注入。
四、依赖注入的示例下面通过一个简单的示例来说明依赖注入的用法。
假设我们有一个UserService接口和一个UserServiceImpl实现类,代码如下:```public interface UserService {void saveUser();}public class UserServiceImpl implements UserService {public void saveUser() {System.out.println("保存用户信息");}}```我们可以通过构造函数注入依赖关系,代码如下:```public class UserController {private UserService userService;public UserController(UserService userService) { erService = userService;}public void save() {userService.saveUser();}}```在上面的例子中,UserController类通过构造函数接收一个UserService对象,并将其保存在成员变量userService中。
浅谈springDI依赖注⼊⽅式和区别⽬录springDI3种DI注解的区别1@Autowired2@Inject3@Resource3种注⼊⽅式的区别1field注⼊2构造器注⼊3setter注⼊构造器注⼊的好处1依赖不可变2依赖不为空3完全初始化状态4避免循环依赖5总结spring DISpring框架对Java开发的重要性不⾔⽽喻,其核⼼特性就是IOC(Inversion of Control,控制反转)和AOP,平时使⽤最多的就是其中的IOC,我们通过将组件交由Spring的IOC容器管理,将对象的依赖关系由Spring控制,避免硬编码所造成的过度程序耦合。
3种DI注解的区别1 @Autowired使⽤特点Autowired注解是spring框架提供的Autowired注解优先byType获取java bean,其次byNameAutowired注解配合Qualifier注解区分java bean的名称,主要⽤于同⼀个类型的javabean有多个实Autowired注解注⼊的对象,⼀般要求⾮null,如果允许为null,需要required=false属性声明@Autowired可以作⽤在变量、setter⽅法、构造函数上使⽤过程a、将@autowored写在被注⼊的成员变量上,就不⽤再xml⽂件中配置了,在程序中去掉相应的setter和getter⽅法,b、还可以写在构造⽅法上、setter⽅法上c、@Qualifier@Qualifier("XXX") 中的 XX是 Bean 的名称,所以 @Autowired 和 @Qualifier 结合使⽤时,⾃动注⼊的策略就从 byType 转变成 byName 了。
不过需要注意的是@Autowired 可以对成员变量、⽅法以及构造函数进⾏注释,⽽ @Qualifier 的标注对象是成员变量、⽅法⼊参、构造函数⼊参。
2 @Inject使⽤特点@Inject是JSR330 (Dependency Injection for Java)中的规范,需要导⼊javax.inject.Inject; 实现注⼊@Inject是根据类型进⾏⾃动装配的,如果需要按名称进⾏装配,则需要配合@Named@Inject可以作⽤在变量、setter⽅法、构造函数上与@Autowired使⽤类似,想⽐之下,采⽤spring提供的@Autowired更为普遍使⽤过程a、将@Inject可以作⽤在变量、setter⽅法、构造函数上,和@Autowired⼀样b、@Named@Named("XXX") 中的 XX是 Bean 的名称,所以 @Inject和 @Named结合使⽤时,⾃动注⼊的策略就从 byType 转变成byName 了。
SpringBoot构造器注⼊、Setter⽅法注⼊和Field注⼊对⽐0. 引⼊今天在看项⽬代码的时候发现在依赖注⼊的时候使⽤了构造器注⼊,之前使⽤过 Field 注⼊和 Setter ⽅法注⼊,对构造器注⼊不是很了解。
经过查阅资料看到,Spring 推荐使⽤构造器注⼊的⽅式,下⾯介绍构造器注⼊到底有什么⽞机。
1. 常见的三种注解注⼊⽅式对⽐Field 注⼊@Controllerpublic class HelloController {@Autowiredprivate AlphaService alphaService;@Autowiredprivate BetaService betaService;}field 注⼊⽅式是使⽤最多的,原因是这种⽅式使⽤起来⾮常简单,代码更加简洁。
Setter ⽅法注⼊@Controllerpublic class HelloController {private AlphaService alphaService;private BetaService betaService;@Autowiredpublic void setAlphaService(AlphaService alphaService) {this.alphaService = alphaService;}@Autowiredpublic void setBetaService(BetaService betaService) {this.betaService = betaService;}}在 Spring 3.x 刚推出的时候,Spring 官⽅在对⽐构造器注⼊和 Setter 注⼊时,推荐使⽤ Setter ⽅法注⼊:The Spring team generally advocates setter injection, because large numbers of constructor arguments can get unwieldy, especially when properties are optional. Setter methods also make objects of that class amenable to reconfiguration or re-injection later. Management through is a compelling use case.Some purists favor constructor-based injection. Supplying all object dependencies means that the object is always returned to client (calling) code ina totally initialized state. The disadvantage is that the object becomes less amenable to reconfiguration and re-injection.意思是说,当出现很多注⼊项的时候,构造器参数可能会变得臃肿,特别是当参数时可选的时候。
详解Spring依赖注⼊:@Autowired,@Resource和@Inject区别与实现原理⼀、spring依赖注⼊使⽤⽅式@Autowired是spring框架提供的实现依赖注⼊的注解,主要⽀持在set⽅法,field,构造函数中完成bean注⼊,注⼊⽅式为通过类型查找bean,即byType的,如果存在多个同⼀类型的bean,则使⽤@Qualifier来指定注⼊哪个beanName的bean。
与JDK的@Resource的区别:@Resource是基于bean的名字,即beanName,来从spring的IOC容器查找bean注⼊的,⽽@Autowried是基于类型byType来查找bean注⼊的。
与JDK的@Inject的区别:@Inject也是基于类型来查找bean注⼊的,如果需要指定名称beanName,则可以结合使⽤@Named注解,⽽@Autowired是结合@Qualifier注解来指定名称beanName。
⼆、spring依赖注⼊注解的实现原理注解处理器在spring框架内部实现当中,注解实现注⼊主要是通过bean后置处理器BeanPostProcessor接⼝的实现类来⽣效的。
BeanPostProcessor后置处理器是在spring容器启动时,创建bean对象实例后,马上执⾏的,对bean对象实例进⾏加⼯处理。
@Autowired是通过BeanPostProcessor接⼝的实现类AutowiredAnnotationBeanPostProcessor来实现对bean对象对其他bean对象的依赖注⼊的;@Resource和@Inject是通过BeanPostProcessor接⼝的实现类CommonAnnotationBeanPostProcessor来实现的,其中如名字所述,即公共注解CommonAnotation,CommonAnnotationBeanPostProcessor是spring中统⼀处理JDK中定义的注解的⼀个BeanPostProcessor。
通过注解的方式给对象注入属性通过Spring的xml配置文件可以定义一个bean,其定义一个bean的方式如下<bean id=”取名”class=”类的全限定名称”></bean>然而通过注解的方式也可以定义一个bean有四种注解可以定义一个bean,通常认为的分配在不同的层面上,但是它们的作用是完全一样的//通过以下方式可以定义一个bean,@Component@Controller //声明在控制层的bean@Service //声明在业务层的bean@Repository //声明在数据访问层的bean当然在applicatonContext.xml配置文件中需要声明,采用注解是配合扫描一起使用的,需要在配置文件中告知:<context:component-scan base-package=”包名”></context:component-scan>①@Repositorypublic class UserDao {}②这样便表示定义一个bean就如在xml文件中<bean id=”userDao”class=”com.workit.h_erDao”></bean>①和②的效果是一样的,如果使用注解引用一个对象,首先需要使用注解关键字定义,表示纳入Spring容器管理,然后在引用对象的那一方在引用的对象上加上注解@Resource表示注入属性:例如:在UserService中引用UserDao对象:首先:将连个类纳入Spring容器管理:由于UserDao是数据库访问层,在UserDao的实现类上使用@Repository注解UserService是业务逻辑层,使用@Service注解在UerService中引用了UserDao对象,需要在属性字段上加上@Resource注解,表示表示给UserService注入UserDao对象属性:public void printInfo();}=========================================================================================== UserDao的实现类UserDaoImpl:@Repositorypublic class UserDaoImpl implements UserDao{@Overridepublic void printInfo() {System.out.println("使用注解:这是UserDao的实现类");}}=========================================================================================== UserService:@Servicepublic class UserService {@Resource (表示给UserService注入UserDao对象属性)private UserDao userDao;public UserDao getUserDao() {return userDao;}public void setUserDao(UserDao userDao) {erDao = userDao;}}========================================================================================== 测试结果:public class TestAnnotation {@Testpublic void testDefinedBean(){ApplicationContext ac = newClassPathXmlApplicationContext("applicationContext.xml",this.getClass());如果是接口,通常注解标在其实现类上:@Rrsource使用于注入依赖的bean:可以通过那么属性制定所需要的bean的名称,或可以通过type属性制定所需要的bean的类型,如果只有一个bean匹配这个类型,则就是它,如果有多个bean匹配这个类型或可以什么都不指定,默认是先按当前字段或属性名称查找,如果找不到,则按类型查找如果有多个bean类型都相同,那么就匹配名字相同的,如果名字都不想同,则抛出异常。
Spring各种注解的含义及⽤法(持续更新)1.基础(SpringMVC和SpringBoot都有在⽤)@Controller通常⽤于标注在控制层类上。
@Service通常⽤于标注在业务层实现类上。
可以设置⾃定义service类的别名,在控制层引⼊时就需要根据设置的别名进⾏引⼊。
@Mapper不需要在启动类上配置扫描,会在运⾏时通过动态代理⽣成实现类。
@Component泛指组件,当组件不好归属于控制层/业务层的时候,我们可以使⽤这个注解进⾏标注@ServletComponentScan在SpringBootApplication上使⽤@ServletComponentScan注解后,Servlet、Filter、Listener可以直接通过@WebServlet、@WebFilter、@WebListener注解⾃动注册,⽆需其他代码@ComponentScan(basePackages ={'可配置扫描的路径"})扫描配置路径中的类,⽣成实现类,把依赖的组件注⼊进去@Autowired关联依赖的组件,当该组件接⼝有2个以上的实现类时,须添加 @Qualifier("实现类的名称") 说明具体是哪个实现类使⽤了该注解可不⽤写get set⽅法 Spring会帮你完成@Primary当2个类实现同⼀个接⼝时,在使⽤改接⼝时,把这个注解加在其中⼀个实现类上,就会优先选择使⽤改注解的类@Scope("prototype")默认是singleton单例模式的,prototype表⽰每次调⽤时都会创建⼀个新的对象@Bean注解将会告诉 Spring 其修饰的⽅法将会返回⼀个对象,该⽅法要注册为 Spring 应⽤上下⽂的 bean,默认情况下bean 的 ID 与带有 @Bean 注解的⽅法名保持⼀致。
可以 @Bean(name="定义其他名称")@Configuration标注在类上,相当于把该类作为spring的xml配置⽂件中的,作⽤为:配置spring容器(应⽤上下⽂) @Configuration注解的spring容器加载⽅式,⽤AnnotationConfigApplicationContext替换ClassPathXmlApplicationContextApplicationContext context = new AnnotationConfigApplicationContext(TestConfiguration.class);如果加载spring-context.xml⽂件:ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");@Param标记在dao层⽅法中的普通参数前,可以在xml中不需要使⽤ parameterType 进⾏声明可以直接使⽤,标记在实体类参数前,需要在xml中使⽤别名.属性的⽅式使⽤实体类的变量,建议实体类参数不加,不加可以在xml中直接使⽤变量名。
Spring对于Bean的依赖注入,支持多种注解方式:
直观上看起来,@Autowired是Spring提供的注解,其他几个都是JDK本身内建的注解,Spring 对这些注解也进行了支持。
但是使用起来这三者到底有什么区别呢?笔者经过方法的测试,发现一些有意思的特性。
区别总结如下:
一、@Autowired有个required属性,可以配置为false,这种情况下如果没有找到对应的bean 是不会抛异常的。
@Inject和@Resource没有提供对应的配置,所以必须找到否则会抛异常。
二、@Autowired和@Inject基本是一样的,因为两者都是使用AutowiredAnnotationBeanPostProcessor来处理依赖注入。
但是@Resource是个例外,它使用的是CommonAnnotationBeanPostProcessor来处理依赖注入。
当然,两者都是BeanPostProcessor。
TIPS Qualified name VS Bean name
在Spring设计中,Qualified name并不等同于Bean name,后者必须是唯一的,但是前者类似于tag或者group的作用,对特定的bean进行分类。
可以达到getByTag(group)的效果。
对于XML配置的bean,可以通过id属性指定bean name(如果没有指定,默认使用类名首字母小写),通过标签指定qualifier name:
如果是通过注解方式,那么可以通过@Qualifier注解指定qualifier name,通过@Named或者@Component(@Service,@Repository等)的value值指定bean name:
或者
同样,如果没有指定bean name,那么Spring会默认是用类名首字母小写
(Lamborghini=>lamborghini)。
三、通过Anotation注入依赖的方式在XML注入方式之前进行。
如果对同一个bean的依赖同时使用了两种注入方式,那么XML的优先。
但是不同担心通过Anotation注入的依赖没法注入XML中配置的bean,依赖注入是在bean的注册之后进行的。
四、目前的autowired by type方式(笔者用的是3.2.3.RELEASE版本),Spring的AutowiredAnnotationBeanPostProcessor实现都是有”bug”的,也就是说@Autowired和@Inject 都是有坑的(称之为坑,不称之为bug是因为貌似是故意的。
)。
这是来源于线上的一个bug,也是这边文章的写作原因。
现场如下:
application-context.xml中有如下定义:
其中static-field应用的常量定义在如下类中:
然后如果我们在代码中如下声明依赖:
Guess what,诡异的事情发生了!运行结果如下:
也就是说Map
debug了一下,发现确实是Spring的一个bug。
在DefaultListableBeanFactory的这个方法出问题了:
关键在这一句:Map
debug了一下,发现跟没有指定qualifie name是一样的执行路径。
不是指定了bean name了吗?为什么还是autowired by type呢?仔细查看了一下才发现。
DefaultListableBeanFactory 的doResolveDependency方法对首先对类型做了区别:
如果是Array,Collection或者Map,则根据集合类中元素的类型来进行autowired by type(Map 使用value的类型)。
为什么这么特殊处理呢?原来,Spring是为了达到这样的目的:让你可以一次注入所有符合类型的实现,也就是说可以这样子注入:
如果你的car有多个实现,那么都会注入进来,不会再报
然而,上面的情况如果你用@Resource则不会有这个问题:
正常运行:
当然,你如果不指定@Qualifier(“languageChangesMap”),同时field name不是languageChangesMap,那么还是一样报错的。
而且,@Resource也可以实现上面的List接收所有实现:
运行的妥妥的:
这是因为@Resource注解使用的是CommonAnnotationBeanPostProcessor处理器,跟AutowiredAnnotationBeanPostProcessor不是同一个作者[/偷笑]。
这里就不分析了,感兴趣的同学可以自己看代码研究一下。
最终结论如下:
1、@Autowired和@Inject
2、@Resource
测试工程保存在GitHub上,是标准的maven工程,感兴趣的同学可以clone到本地运行测试一下。
补充
有同事指出Spring官方文档上有这么一句话跟我的结有点冲突:
也就是说@Autowired即使加了@Qualifier注解,其实也是autowired by type。
@Qualifier只是一个限定词,过滤条件而已。
重新跟进了一下代码,发现确实是这样子的。
Spring设计的这个@Qualifier name 并不等同于bean name。
他有点类似于一个tag。
不过如果这个tag 是唯一的化,那么其实效果上等同于bean name。
实现上,Spring是先getByType,得到list candicates,然后再根据qualifier name进行过滤。
再定义一个兰博基尼,这里使用@Qualifier指定:
再定义一个劳斯莱斯,这里故意用@Named指定:
测试一下注入定义的豪华车:
运行结果如下:
补充:Autowiring modes
Spring支持四种autowire模式,当使用XML配置方式时,你可以通过autowire属性指定。
如果使用@Autowired、@Inject或者@Resource注解的时候,则稍微复杂一些,会有一个失败退化过程,并且引入了Qualifier。
不过基本原理是一样。