我们使用面向对象编程 , 对象的创建与对象间的依赖关系 完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为 所谓控制反转就是:获得依赖对象的方式反转了。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现 控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
5.1Bean的自动装配注解
5.1.1@Autowired、@Qualifier、@Resource
- 自动装配是使用spring满足bean依赖的一种方法
- spring会在应用上下文中为某个bean寻找其依赖的bean。
Spring中bean有三种装配机制,分别是:
- 在xml中显式配置;
- 在java中显式配置;
- 隐式的bean发现机制和自动装配。
笔记主要为第三种:自动化的装配bean。
Spring的自动装配需要从两个角度来实现,或者说是两个操作:
- 组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
- 自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;
组件扫描和自动装配组合发挥巨大威力,使的显示的配置降低到最少。
推荐不使用自动装配xml配置 , 而使用注解 .
5.1.1.1新建项目
- 新建实体类
public class Cat {
public void shout() {
System.out.println("miao~");
}
}
package com.node.pojo;
public class Dog {
public void shout() {
System.out.println("wang~");
}
}
package com.node.pojo;
public class User {
private Cat cat;
private Dog dog;
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
return "User{" +
"cat=" + cat +
", dog=" + dog +
'}';
}
}
- 配置
<bean id="dog" class="com.node.pojo.Dog"/>
<bean id="cat" class="com.node.pojo.Cat"/>
<bean id="user" class="com.node.pojo.User">
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
</bean>
- 测试
public class Mytest {
@Test
public void User(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean("user", User.class);
user.getCat().shout();
user.getDog().shout();
}
}
5.1.1.2byName
autowire byName (按名称自动装配)
由于在手动配置xml过程中,常常发生字母缺漏和大小写等错误,而无法对其进行检查,使得开发效率降低。
采用自动装配将避免这些错误,并且使配置简单化。
<bean id="dog" class="com.node.pojo.Dog"/>
<bean id="cat" class="com.node.pojo.Cat"/>
<bean id="user" class="com.node.pojo.User" autowire="byName">
</bean>
需要看set方法,如果setDog,则id为dog或Dog
如果setDog11,则id为dog11
5.1.1.3byType
autowire byType (按类型自动装配)
使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。
<bean id="dog" class="com.node.pojo.Dog"/>
<bean id="cat" class="com.node.pojo.Cat"/>
<bean id="cat2" class="com.node.pojo.Cat"/>
<bean id="user" class="com.node.pojo.User" autowire="byType">
</bean>
- 测试,报错:NoUniqueBeanDefinitionException
删掉cat2或则删掉cat,也或者将cat的bean名称改掉(把id="cat"删掉)!测试!因为是按类型装配,所以并不会报异常,也不影响最后的结果。甚至将id属性去掉,也不影响结果。找到这个类型即可
5.1.2使用注解
jdk1.5开始支持注解,spring2.5开始全面支持注解。
准备工作: 利用注解的方式注入属性。
- 在spring配置文件中引入context文件头
xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
- 开启属性注解支持!
<context:annotation-config/>
5.1.2.1 @Autowired
- @Autowired是按类型自动转配的,不支持id匹配。
- 需要导入 spring-aop的包!
5.1.2.2测试
- 将User类中的set方法去掉,使用@Autowired注解
package com.node.pojo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import javax.annotation.Resource;
public class User {
@Autowired
@Autowired(required = false)// 说明: false,对象可以为null;true,对象必须存对象,不能为null。默认为true
private Cat cat;
@Autowired
private Dog dog;
public Cat getCat() {
return cat;
}
public Dog getDog() {
return dog;
}
@Override
public String toString() {
return "User{" +
"cat=" + cat +
", dog=" + dog +
'}';
}
}
- 配置文件
<context:annotation-config/>
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat" class="com.kuang.pojo.Cat"/>
<>
5.1.2.3@Qualifier
- @Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配
- @Qualifier不能单独使用。
5.1.2.4测试
- 配置文件修改内容,保证类型存在对象。且名字不为类的默认名字!
<bean id="dog1" class="com.kuang.pojo.Dog"/>
<bean id="dog2" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>
- 这样运行没有加@Qualifie注解就会报错,则
@Autowired
@Qualifier(value = "cat2")
private Cat cat;
@Autowired @Qualifier(value = "dog2")
private Dog dog;
5.1.2.5@Resource
- @Resource如有指定的name属性,先按该属性进行byName方式查找装配;
- 其次再进行默认的byName方式进行装配;
- 如果以上都不成功,则按byType的方式自动装配。
- 都不成功,则报异常。
package com.node.pojo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import javax.annotation.Resource;
public class User {
@Resource
private Cat cat;
@Resource
private Dog dog;
public Cat getCat() {
return cat;
}
public Dog getDog() {
return dog;
}
@Override
public String toString() {
return "User{" +
"cat=" + cat +
", dog=" + dog +
'}';
}
}
5.1.3小结
@Autowired与@Resource异同:
- @Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。
- @Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果 要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我 们想使用名称装配可以结合@Qualifier注解进行使用
- @Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果 没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在 setter方法上默认取属性名进行装配。 当找不到与名称匹配的bean时才按照类型进行装配。但是 需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
- 它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先 byName。
5.2 Bean的属性注入
5.2.1@Component、@Value
- User.java
@Component// 组件 相当于配置文件中 <bean id="user" class="当前注解的类"/>
@Scope("singleton") //作用域:单例模式(singleton) 多例模式(prototype)
public class User {
@Value("mmm~")
public String Cat;
@Value("www~")
public String dog;
}
- applicationContext.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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd"
>
<context:component-scan base-package="com.node.pojo"/>
<context:annotation-config/>
</beans>
- Mytest.java
public class Mytest {
@Test
public void User(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean("user", User.class);
System.out.println(user.Cat);
System.out.println(user.dog);
}
}
5.3 Bean的衍生注解
5.3.1@Controller、@Service、@Repository
我们这些注解,就是替代了在配置文件当中配置步骤而已
!更加的方便快捷!
@Component三个衍生注解
为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。
- @Controller:web层 连接层
- @Service:service层 业务层
- @Repository:dao层 接口 写上这些注解,就相当于将这个类交给Spring管理装配了!
- UserController.java
@Controller
public class UserController {
@Value("111")
public String a;
}
- UserDao
@Repository
public class UserDao {
@Value("222")
public String b;
}
- UserService
@Service
public class UserService {
@Value("333")
public String c;
}
- applicationContext.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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.node"/>
<context:annotation-config/></beans>
- Mytest.java
public class Mytest {
@Test
public void User(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = context.getBean("userDao", UserDao.class);
System.out.println(userDao.b);
}
}
5.4 基于Java类(显式)的进行配置(全注解)
5.4.1 @Configuration
JavaConfig 原来是 Spring 的一个子项目,它通过 Java 类的方式提供 Bean 的定义信息,在 Spring4 的 版本, JavaConfig 已正式成为 Spring4 的核心功能 。
- Myconfig.java
@Configuration
public class Myconfig {
@Bean//把当前方法的返回值作为bean对象存入spring的ioc容器中
public Dog dog(){
return new Dog();
}
}
- Dog.java
@Component
public class Dog {
public String name = "dog";
}
- Mytest.java
public class Mytest {
@Test
public void mytest(){
ApplicationContext applicationContext=new
AnnotationConfigApplicationContext(Myconfig.class);
Dog dog=applicationContext.getBean("dog",Dog.class);
System.out.println(dog.name);}
}
5.4.2 导入其他配置
- Myconfig2.java
@Configuration //代表这是一个配置类
public class MyConfig2 {
}
- 在之前的配置类中我们来选择导入这个配置类
@Configuration
@Import(MyConfig2.class) //导入合并其他配置类,类似于配置文件中的 inculde 标签
public class MyConfig {
@Bean
public Dog dog(){
return new Dog();
}
}
关于这种Java类的配置方式,我们在之后的SpringBoot 和 SpringCloud中还会大量看到,我们需要知道 这些注解的作用即可!
5.5总结
5.5.1XML与注解比较
- XML可以适用任何场景 ,结构清晰,维护方便
- 注解不是自己提供的类使用不了,开发简单方便
5.5.2xml与注解整合开发 :推荐最佳实践
- xml管理Bean
- 注解完成属性注入
- 使用过程中, 可以不用扫描,扫描是为了类上的注解
<context:annotation-config/>
作用:
- 进行注解驱动注册,从而使注解生效
- 用于激活那些已经在spring容器里注册过的bean上面的注解,也就是显示的向Spring注册
- 如果不扫描包,就需要手动配置bean
- 如果不加注解驱动,则注入的值为null!
6.模拟整合
/**
* Spring练习
* 1、新建一个Admin类
* 有loginName、passWord 这两个属性
* 2、新建LoginDao
* 有getAdmin()方法,返回一个注入进来的Admin对象
* 3、新建loginService
* 有isLogin(String loginName,int password)
* 从dao获取管理员信息,对比用户名密码是否正确
* 返回登入成功或失败
* 4、新建LoginController
* 有toLogin(String lname,int pwd)方法
* 返回登入状态
* 测试类
* 加载Spring配置文件,实现输入登入名与密码输出登录状态
*/
6.1 Pom
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
6.2 LoginDao
package com.node.dao;
import com.node.pojo.Admin;
public class LoginDao {
private Admin admin;
public void setAdmin(Admin admin) { //通过Set注入
this.admin = admin;
}
public Admin getAdmin(){
System.out.println(admin);
return admin;
}
}
6.3 LoginService
package com.node.service;
import com.node.dao.LoginDao;
import com.node.pojo.Admin;
public class LoginService {
private LoginDao loginDao;
public void setLoginDao(LoginDao loginDao) { //通过set注入
this.loginDao = loginDao;
}
public boolean isLogin(String loginName, int password){
Admin admin= loginDao.getAdmin();
if (admin.getLoginName()!=loginName&&admin.getPassword()!=password){
return false;
}else
return true;
}
}
6.4 LoginController
package com.node.controller;
import com.node.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
public class LoginController {
@Autowired
LoginService service; //通过注解注入 需在xml文件导入头文件并开启注解
public boolean toLogin(String lname, int pwd){
boolean i=service.isLogin(lname,pwd);
if (i){
return true;
}else
return false;
}
}
6.5 Test
package com.node;
import com.node.controller.LoginController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
ApplicationContext context1 = new ClassPathXmlApplicationContext("beans.xml");
LoginController loginController = (LoginController) context1.getBean("LoginController");
Scanner s=new Scanner(System.in);
String name=s.next();
int pa=s.nextInt();
boolean i= loginController.toLogin(name,pa);
System.out.println(i);
}
}
6.6 beans.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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
"
xmlns:context="http://www.springframework.org/schema/context"
>
//开启注解
<context:annotation-config/>
<bean id="Admin" class="com.node.pojo.Admin">
<property name="loginName" value="123"></property>
<property name="password" value="123456"></property>
</bean>
<bean id="LoginDao" class="com.node.dao.LoginDao">
<property name="admin" ref="Admin"></property>
</bean>
<bean id="LoginService" class="com.node.service.LoginService">
<property name="loginDao" ref="LoginDao"></property>
</bean>
<bean id="LoginController" class="com.node.controller.LoginController"></bean>
</beans>