Spring 自动装配(基于xml配置文件)
Spring 的自动装配功能可以让 Spring 容器依据某种规则(自动装配的规则,有五种),为指定的 Bean 从应用的上下文(AppplicationContext 容器)中查找它所依赖的 Bean,并自动建立 Bean 之间的依赖关系。而这一过程是在完全不使用任何 和 元素 ref 属性的情况下进行的。
Spring 的自动装配功能能够有效地简化 Spring 应用的 XML 配置,因此在配置数量相当多时采用自动装配降低工作量。
Spring 框架式默认不支持自动装配的,要想使用自动装配,则需要对 Spring XML 配置文件中 元素的 autowire 属性进行设置
Spring 共提供了 5 中自动装配规则,它们分别与 autowire 属性的 5 个取值对应
不使用自动装配(autowire=“no”)
autowire=“no” 表示不使用自动装配,此时我们必须通过 <bean> 元素的 <constructor-arg>和 <property> 元素的 ref 属性维护 Bean 的依赖关系
Dept部门类
public class Dept { private Integer id; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Dept{" + "id=" + id + ", name='" + name + '\'' + '}'; } }
Employee员工类
public class Employee { private Integer E_id; private String name; private Dept dept; public Integer getE_id() { return E_id; } public void setE_id(Integer e_id) { E_id = e_id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Dept getDept() { return dept; } public void setDept(Dept dept) { this.dept = dept; } @Override public String toString() { return "Employee{" + "E_id=" + E_id + ", name='" + name + '\'' + ", dept=" + dept + '}'; } }
autowire="no"
<?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"> <!--管理DEPT--> <bean id="dept" class="com.liu.pojo.Dept"> <property name="id" value="1"/> <property name="name" value="技术部"/> </bean> <!--管理员工--> <bean id="employee" class="com.liu.pojo.Employee" autowire="no"> <property name="e_id" value="1"/> <property name="name" value="李白"/> <property name="dept" ref="dept"/> </bean> </beans>
Test
public class AutoDITest { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); Employee employee = context.getBean("employee", Employee.class); System.out.println(employee); } }
结果
Employee{E_id=1, name='李白', dept=Dept{id=1, name='技术部'}} 1
按名称自动装配(autowire=“byName”)
autowire=“byName” 表示按属性名称自动装配,XML 文件中 Bean 的 id 或 name 必须与类中的属性名称相同。
<!--管理DEPT--> <bean id="dept" class="com.liu.pojo.Dept"> <property name="id" value="1"/> <property name="name" value="技术部"/> </bean> <!--管理员工--> <bean id="employee" class="com.liu.pojo.Employee" autowire="byName"> <property name="e_id" value="1"/> <property name="name" value="李白"/> </bean>
Employee{E_id=1, name='李白', dept=Dept{id=1, name='技术部'}}
如果名字不一样,比如改下dept的id,则就会注入不成功,部门为null
<!--管理DEPT--> <bean id="dept1" class="com.liu.pojo.Dept"> <property name="id" value="1"/> <property name="name" value="技术部"/> </bean> <!--管理员工--> <bean id="employee" class="com.liu.pojo.Employee" autowire="byName"> <property name="e_id" value="1"/> <property name="name" value="李白"/> </bean>
Employee{E_id=1, name='李白', dept=null}
按类型自动装配(autowire=“byType”)
autowire=“byType” 表示按类中对象属性数据类型进行自动装配。即使 XML 文件中 Bean 的 id 或 name 与类中的属性名不同,只要 Bean 的 class 属性值与类中的对象属性的类型相同,就可以完成自动装配。
<!--管理DEPT--> <bean id="dept1" class="com.liu.pojo.Dept"> <property name="id" value="1"/> <property name="name" value="技术部"/> </bean> <!--管理员工--> <bean id="employee" class="com.liu.pojo.Employee" autowire="byType"> <property name="e_id" value="1"/> <property name="name" value="李白"/> </bean>
现在虽然id不一样了,但是是按照类型进行注入的,需要com.liu.pojo.Dept类型的,去spring工厂里找,咦,找到了,就把找到这个bean注入给需要的bean,如果没找到,就无法注入
Employee{E_id=1, name='李白', dept=Dept{id=1, name='技术部'}}
如果同时存在多个相同类型的 Bean,则注入失败,并且引发异常。
IDEA还是很智能的,直接提示了,并且这样运行也会报错,因为spring也蒙蔽了,他也不知道要注入哪个bean了,他解决不了这个问题,就报错了
构造函数自动装配(autowire=“constructor”)
autowire=“constructor” 表示按照 Java 类中构造函数进行自动装配。
<!--管理DEPT--> <bean id="dept1" class="com.liu.pojo.Dept"> <constructor-arg name="id" value="1"/> <constructor-arg name="name" value="技术部"/> </bean> <!--管理员工--> <bean id="employee" class="com.liu.pojo.Employee" autowire="constructor"> <constructor-arg index="0" value="1"/> <constructor-arg index="1" value="李白"/> </bean>
Employee{E_id=1, name='李白', dept=Dept{id=1, name='技术部'}}
默认的自动装配模式(autowire=“default”)
<!--管理DEPT--> <bean id="dept1" class="com.liu.pojo.Dept"> <property name="id" value="1"/> <property name="name" value="技术部"/> </bean> <!--管理员工--> <bean id="employee" class="com.liu.pojo.Employee" autowire="default"> <property name="e_id" value="1"/> <property name="name" value="李白"/> </bean>
Employee{E_id=1, name='李白', dept=Dept{id=1, name='技术部'}}
Spring自动装配 (基于注解)
从 Java 5 开始,Java 增加了对注解(Annotation)的支持,它是代码中的一种特殊标记,可以在编译、类加载和运行时被读取,执行相应的处理。开发人员可以通过注解在不改变原有代码和逻辑的情况下,在源代码中嵌入补充信息。
Spring 从 2.5 版本开始提供了对注解技术的全面支持,我们可以使用注解来实现自动装配,简化 Spring 的 XML 配置。
Spring 通过注解实现自动装配的步骤如下:
引入依赖
开启组件扫描
使用注解定义 Bean
依赖注入
1. 引入AOP依赖
使用注解的第一步,就是要在项目中引入以下 Jar 包。
org.springframework.core-5.3.13.jar
org.springframework.beans-5.3.13.jar
spring-context-5.3.13.jar
spring-expression-5.3.13.jar
commons.logging-1.2.jar
spring-aop-5.3.13.jar
maven项目直接导入以下依赖坐标即可
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.2.RELEASE</version> </dependency>
2. 开启组件扫描
Spring 默认不使用注解装配 Bean,因此我们需要在 Spring 的 XML 配置中,通过 <context:component-scan> 元素开启 Spring Beans的自动扫描功能。开启此功能后,Spring 会自动从扫描指定的包(base-package 属性设置)及其子包下的所有类,如果类上使用了 @Component 注解,就将该类装配到容器中。
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--xmlns:context="http://www.springframework.org/schema/context" 注意别导错了--> <!--开启组件扫描功能 扫描com.liu包下所有类是否添加了@Component注解--> <context:component-scan base-package="com.liu"/> </beans>
注意:在使用 context:component-scan 元素开启自动扫描功能前,首先需要在 XML 配置的一级标签 中添加 context 相关的约束
3. 使用注解定义 Bean
Spring 提供了以下多个注解,这些注解可以直接标注在 Java 类上,将它们定义成 Spring Bean。
4. 基于注解方式实现依赖注入
我们可以通过以下注解将定义好 Bean 装配到其它的 Bean 中。
1.创建maven工程
2.导入相关依赖在pom.xm配置文件中
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.2.RELEASE</version> </dependency> <!--springmvc核心依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.2.RELEASE</version> </dependency> <!--servlet-api--> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <!--jstl--> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.5</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.3</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--log4j--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.17.1</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.25</version> </dependency> <!--fastjson--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.62</version> </dependency> <!--druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.8</version> </dependency> </dependencies>
3.在 com.liu.dao 包下,创建一个名为 UserDAO 的接口
public interface UserDAO { void print(); }
4.在com.liu.dao.impl 包下,创建 UserDao 的实现类 UserDAOImpl
/*注解 @Repository 将这个dao层类交给spring容器管理 * 尽管我们并没有在spring.xml中进行相应配置,这里的字符串 * value就相当于spring.xml配置bean时的id属性,底层反射代理*/ @Repository(value = "userDAO") public class UserDAOImpl implements UserDAO { @Override public void print() { System.out.println("hello auto"); } }
5.在 com.liu.service 包下,创建一个名为 UserService 的接口
public interface UserService { void out(); }
6.在 com.liu.service.impl 包下,创建 UserService 的实现类 UserServiceImpl
/*这里@Service注解用于标识他是业务层类,然后 * 添加此注解,它就会被spring容器所管理,value * 属性还是同理*/ @Service(value = "userService") public class UserServiceImpl implements UserService { /*这里的@Resource注解是用于依赖注入的,以前我们就是通过配置 * 现在直接在需要的地方,添加相应注解,就实现对他的注入,简化了 * 配置文件的大小以及开发的繁琐,@Resource默认是按照类型进行注入的, * 你也可以指定它的name属性,让他按照name进行注入,或者指定name和 * type这时,他会先按照name进行找,找不到在按照type进行查找,还找不到 * 就会报错了*/ @Resource private UserDAO userDAO; public UserDAO getUserDAO() { return userDAO; } public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; } @Override public void out() { userDAO.print(); System.out.println("我来了"); } }
7. 在 com.liu.controller 包下,创建一个名为 UserController 的类
什么时候给value呢,如果他被其他类需要,或者需要被main调用,就需要给value,就相当于我们在配置文件中给他了一个唯一标识id,然后工厂可以根据id拿到该bean,因为接下来要实例化它,所以给他添加了一个value属性
@Controller("userController") public class UserController { @Resource private UserService userService; public UserService getUserService() { return userService; } public void setUserService(UserService userService) { this.userService = userService; } public void doStr(){ userService.out(); } }
8.创建 Spring 配置文件 Beans.xml,配置内容如下
注意: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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--xmlns:context="http://www.springframework.org/schema/context" 注意别导错了--> <!--开启组件扫描功能 扫描com.liu包下所有类是否添加了@Component注解--> <context:component-scan base-package="com.liu"></context:component-scan> </beans>
9.测试
前端来一个请求,被springmvc拦截,交给了controller,然后controller被spring创建管理,controller的方法调用 service 层,service等去调用 dao 层,完成业务逻辑的处理,返回结果,然而spring为我们做了太多,对象的创建管理,虽然我们没有配置文件xml,但是我们通过注解的方式,注解传入了重要的信息,注解其实就是通过反射去创建对象,单例多例可以看设计模式,还有工厂模式,代理,动态代理,一下子全穿起来吧,是不是觉得豁然开朗,多学,重复写,这种领悟会越来越深刻,越来越清晰,就是在这种状态下进步的,ok
public class Test { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); UserController userController = context.getBean("userController", UserController.class); userController.doStr(); } }
输出
hello auto 我来了