Spring是一个轻量级的控制反转和面向切面的容器框架。
Spring是一个开源的JavaEE应用程序框架;由Rod Johnson发起,是针对JavaBean的生命周期进行管理的轻量级容器;Spring提供了功能强大的IOC、AOP及Web MVC等功能; IOC(Inversion of Control,控制反转):之前在程序中使用new关键字创建对象,而在Spring容器中把创建对象的过程交给Spring进行管理;DI(Dependency Injection,依赖注入):由Spring容器在程序运行中,动态的将某个依赖关系注入到组件中;AOP(Aspect Oriented Programming,面向切面编程):在不修改源代码的情况下,进行功能的增强(CGLIB动态代理类,生成代理类,重写目标类的方法),AOP是OOP的延续,是软件开发中的一个热点,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。 Spring不仅仅能应用于J2EE应用程序中;目的:解决企业应用开发的复杂性;Spring的底层核心部分:
BeansCoreContextExpression所以我们在入门案例中是需要这几个基本的jar包。下面是依赖关系图。
我们创建Maven工程。引入父依赖,子依赖会自动引入,所以可以直接引入spring-context。
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.9.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>创建普通bean类User
public class User { public void add() { System.out.println("add......"); } }创建Spring的配置文件(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"> <!--配置User类的对象--> <bean id="user" class="org.westos.entity.User"> <!--id:对象的名称,class:Bean的全限定类名--> </bean> </beans>测试
@Test public void testAdd() { //1、加载Spring配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); //ClassPathXmlApplicationContext(String configLocation) //resources目录下的文件默认在classes类路径下 //2、获取配置创建的对象 User user = (User) context.getBean("user"); System.out.println(user); user.add(); } //org.westos.entity.User@1a8a8f7c //add......1、xml文件的解析
2、工厂设计模式
3、反射
BeanFactory和ApplicationContext接口,功能相似。
1、BeanFactory
IOC容器的基本实现,是Spring内部使用的一个接口,一般不提供给开发人员进行使用。
加载配置文件时,不会创建对象,当你在获取时,才会去创建对象。
2、ApplicationContext
BeanFactory的子接口,提供了比BeanFactory更多更强大的功能,一般面向开发人员使用。
加载配置文件时,就会直接创建对象。
共同点:都可以加载配置文件,创建对象。
因为Spring框架经常会和其他框架结合使用,比如Tomcat的Web项目,所以最好在项目(服务器)启动时把所有资源都准备好,这样可以提高响应速度。
ApplicationContext接口的主要实现类:
IDEA查看接口的实现类快捷键:Ctrl + Alt + B
查看继承关系:Ctrl + H
FileSystemXmlApplicationContext 参数为配置文件的绝对路径 ClassPathXmlApplicationContext 参数为配置文件的类路径Bean管理:指的是下面的两个操作
Spring创建对象Spring注入属性Bean管理操作的两种方式
基于xml配置文件方式基于注解方式1、基于xml配置文件的方式创建对象
在Spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现创建对象;在bean标签中有很多属性,常用的两个是 id:对象在容器中的唯一标识class:对象所属类的全限定类名 创建对象时,默认执行的是无参构造方法;2、基于xml配置文件的方式注入属性
DI:依赖注入,注入属性,应该在创建对象的基础之上;使用set方法注入;使用有参构造器注入;Bean
public class Student { private String studentNo; private String studentName; public Student() { System.out.println("Student无参构造执行了"); } /** * 使用set方法注入属性 * @param studentNo 学号 */ public void setStudentNo(String studentNo) { this.studentNo = studentNo; } /** * 使用set方法注入属性 * @param studentName 学生姓名 */ public void setStudentName(String studentName) { this.studentName = studentName; } public void show() { System.out.println("show..."); } @Override public String toString() { return "Student{" + "studentNo='" + studentNo + '\'' + ", studentName='" + studentName + '\'' + '}'; } }bean.xml
<!--使用set注入属性--> <bean id="student" class="org.westos.entity.Student"> <!--使用property标签完成属性注入--> <property name="studentNo" value="01172100"/> <property name="studentName" value="张三"/> </bean>测试
@Test public void test1() { //测试set方法注入属性 ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); Student student = (Student) context.getBean("student"); System.out.println(student); //Student无参构造执行了 //Student{studentNo='01172100', studentName='张三'} }Bean
public class Book { private String bookName; private double bookPrice; public Book() { } public Book(String bookName, double bookPrice) { this.bookName = bookName; this.bookPrice = bookPrice; System.out.println("Book有参构造执行了"); } @Override public String toString() { return "Book{" + "bookName='" + bookName + '\'' + ", bookPrice=" + bookPrice + '}'; } }bean.xml
<!--使用有参构造注入属性--> <bean id="book" class="org.westos.entity.Book"> <constructor-arg name="bookName" value="白夜行"/> <constructor-arg name="bookPrice" value="55.5"/> </bean>测试
@Test public void test1() { ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); Book book = (Book) context.getBean("book"); System.out.println(book); //Student无参构造执行了 //Book有参构造执行了 //Book{bookName='白夜行', bookPrice=55.5} }简化set方法注入属性的方式。
1、添加p名称空间在xml文件的约束中
Bean
public class Order { private String orderId; private String orderName; public Order() { System.out.println("Order无参构造执行"); } public void setOrderId(String orderId) { this.orderId = orderId; } public void setOrderName(String orderName) { this.orderName = orderName; } @Override public String toString() { return "Order{" + "orderId='" + orderId + '\'' + ", orderName='" + orderName + '\'' + '}'; } }bean.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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--使用set注入属性--> <bean id="student" class="org.westos.entity.Student"> <!--使用property标签完成属性注入--> <property name="studentNo" value="01172100"/> <property name="studentName" value="张三"/> </bean> <!--使用有参构造注入属性--> <bean id="book" class="org.westos.entity.Book"> <constructor-arg name="bookName" value="白夜行"/> <constructor-arg name="bookPrice" value="55.5"/> </bean> <!--使用p命名空间简化set注入属性--> <bean id="order" class="org.westos.entity.Order" p:orderId="202010021623" p:orderName="联想笔记本电脑-拯救者"/> </beans>测试
@Test public void test1() { ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); Order order = (Order) context.getBean("order"); System.out.println(order); //Student无参构造执行了 //Book有参构造执行了 //Order无参构造执行 //Order{orderId='202010021623', orderName='联想笔记本电脑-拯救者'} }简化有参构造器注入属性的方式。
1、添加c名称空间在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:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--使用set注入属性--> <bean id="student" class="org.westos.entity.Student"> <!--使用property标签完成属性注入--> <property name="studentNo" value="01172100"/> <property name="studentName" value="张三"/> </bean> <!--使用有参构造注入属性--> <bean id="book" class="org.westos.entity.Book"> <constructor-arg name="bookName" value="白夜行"/> <constructor-arg name="bookPrice" value="55.5"/> </bean> <!--使用p命名空间简化set注入属性--> <bean id="order" class="org.westos.entity.Order" p:orderId="202010021623" p:orderName="联想笔记本电脑-拯救者"/> <!--使用c命名空间简化有参构造器注入--> <bean id="book1" class="org.westos.entity.Book" c:bookName="解忧杂货店" c:bookPrice="99.9"/> </beans>测试
@Test public void test2() { ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); Book book = (Book) context.getBean("book1"); System.out.println(book); //Student无参构造执行了 --- set property //Book有参构造执行了 --- 有参构造 constructor-arg //Order无参构造执行 --- set p命名空间 //Book有参构造执行了 --- 有参构造 c命名空间 //Book{bookName='解忧杂货店', bookPrice=99.9} }为了不和上面的冲突,重新建立一个Spring的配置文件bean1.xml。
注入空值
<!--给Student的studentName属性设置空值--> <bean id="student2" class="org.westos.entity.Student"> <property name="studentNo" value="04171100"/> <!--向属性中设置null值--> <property name="studentName"> <null/> </property> </bean>测试
@Test public void test2() { //测试注入空值null ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); Student student = (Student) context.getBean("student2"); System.out.println(student); //Student无参构造执行了 //Student{studentNo='04171100', studentName='null'} }属性值中含有特殊符号
<!--Student的属性值包含特殊符号--> <bean id="student3" class="org.westos.entity.Student"> <property name="studentNo" value="02176782"/> <!--1、转义--> <!--<property name="studentName" value="<<李四>>"/>--> <!--2、xml文件的功能,CDATA--> <property name="studentName"> <value><![CDATA[<<李四>>]]></value> </property> </bean>测试
@Test public void test3() { //测试属性值中含有特殊符号 ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); Student student = (Student) context.getBean("student3"); System.out.println(student); //Student无参构造执行了 //Student无参构造执行了 //Student{studentNo='02176782', studentName='<<李四>>'} }为了不和上面的冲突,重新建立一个Spring的配置文件bean2.xml。
public interface StudentDao { /** * 插入 * @param student 学生 */ void insert(Student student); } public class StudentDaoImpl implements StudentDao { @Override public void insert(Student student) { System.out.println("insert"); } } public class StudentService { private StudentDao studentDao; public void setStudentDao(StudentDao studentDao) { this.studentDao = studentDao; } public void insert(Student student) { studentDao.insert(student); } } <?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"> <bean id="studentDaoImpl" class="org.westos.dao.StudentDaoImpl"/> <bean id="studentService" class="org.westos.service.StudentService"> <property name="studentDao" ref="studentDaoImpl"/> </bean> </beans>测试
@Test public void test1() { ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml"); StudentService studentService = (StudentService) context.getBean("studentService"); studentService.insert(new Student()); //Student无参构造执行了 //insert }为了不和上面的冲突,重新建立一个Spring的配置文件bean3.xml。
在数据库中存在一对多的对应关系,比如部门和员工之间。
Department
public class Department { private Integer departmentId; private String departmentName; public void setDepartmentId(Integer departmentId) { this.departmentId = departmentId; } public void setDepartmentName(String departmentName) { this.departmentName = departmentName; } @Override public String toString() { return "Department{" + "departmentId=" + departmentId + ", departmentName='" + departmentName + '\'' + '}'; } }Employee
public class Employee { private String employeeName; private String employeeAge; private Department department; public void setEmployeeName(String employeeName) { this.employeeName = employeeName; } public void setEmployeeAge(String employeeAge) { this.employeeAge = employeeAge; } public void setDepartment(Department department) { this.department = department; } @Override public String toString() { return "Employee{" + "employeeName='" + employeeName + '\'' + ", employeeAge='" + employeeAge + '\'' + ", department=" + department + '}'; } } <?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"> <bean id="emp" class="org.westos.entity.Employee"> <property name="employeeName" value="王五"/> <property name="employeeAge" value="25"/> <property name="department"> <!--内部bean,感觉没有外部bean清晰--> <bean id="department" class="org.westos.entity.Department"> <property name="departmentId" value="001"/> <property name="departmentName" value="人工智能部"/> </bean> </property> </bean> </beans>测试
@Test public void test1() { //测试注入内部Bean ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml"); Employee employee = (Employee) context.getBean("emp"); System.out.println(employee); //Employee{employeeName='王五', employeeAge='25', department=Department{departmentId=1, departmentName='人工智能部'}} }级联赋值
<!--级联赋值--> <bean id="employee" class="org.westos.entity.Employee"> <property name="employeeName" value="赵六"/> <property name="employeeAge" value="26"/> <property name="department" ref="department2"/> <property name="department.departmentName" value="云平台部"/> <!--这样做会修改原有bean的属性值--> </bean> <bean id="department2" class="org.westos.entity.Department"> <property name="departmentId" value="002"/> <property name="departmentName" value="大数据部"/> </bean>注意:必须提供Employee类中department属性的get方法。
public Department getDepartment() { return department; } @Test public void test2() { //测试级联赋值 ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml"); Employee employee = (Employee) context.getBean("employee"); System.out.println(employee); //Employee{employeeName='赵六', employeeAge='26', department=Department{departmentId=2, departmentName='云平台部'}} Department department = (Department) context.getBean("department2"); System.out.println(department); //Department{departmentId=2, departmentName='云平台部'} }为了不和上面的冲突,重新建立一个Spring的配置文件bean4.xml。
public class CollectionDemo { private String[] names; private List<Integer> scores; private Map<String,Student> students; private Set<String> ids; public String[] getNames() { return names; } public void setNames(String[] names) { this.names = names; } public List<Integer> getScores() { return scores; } public void setScores(List<Integer> scores) { this.scores = scores; } public Map<String, Student> getStudents() { return students; } public void setStudents(Map<String, Student> students) { this.students = students; } public Set<String> getIds() { return ids; } public void setIds(Set<String> ids) { this.ids = ids; } @Override public String toString() { return "CollectionDemo{" + "names=" + Arrays.toString(names) + ", scores=" + scores + ", students=" + students + ", ids=" + ids + '}'; } } <?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"> <bean id="collectionDemo" class="org.westos.entity.CollectionDemo"> <!--数组类型属性注入--> <property name="names"> <!--array或者list--> <list> <value>张三</value> <value>李四</value> </list> </property> <!--List类型属性注入--> <property name="scores"> <list> <value>80</value> <value>87</value> <value>88</value> </list> </property> <!--Map类型属性注入--> <property name="students"> <map> <entry key="张三"> <!--当值是一个对象时,可以引入外部的bean,使用ref标签--> <!--<ref bean="student"/>--> <bean class="org.westos.entity.Student"> <property name="studentNo" value="01278641"/> <property name="studentName" value="张三"/> </bean> </entry> <entry key="李四"> <bean class="org.westos.entity.Student"> <property name="studentNo" value="12671628"/> <property name="studentName" value="李四"/> </bean> </entry> </map> </property> <!--Set类型属性注入--> <property name="ids"> <set> <value>string</value> <value>integer</value> <value>char</value> </set> </property> </bean> </beans>测试
@Test public void test1() { //测试集合类型注入 ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml"); CollectionDemo demo = (CollectionDemo) context.getBean("collectionDemo"); System.out.println(demo); //Student无参构造执行了 //Student无参构造执行了 //CollectionDemo{names=[张三, 李四], scores=[80, 87, 88], students={张三=Student{studentNo='01278641', studentName='张三'}, // 李四=Student{studentNo='12671628', studentName='李四'}}, ids=[string, integer, char]} }此时,如果想要把集合提取为一个公共部分,可以使用下面的方式。
public class CollectionDemo2 { private List<Student> list; public List<Student> getList() { return list; } public void setList(List<Student> list) { this.list = list; } }为了不和上面的冲突,重新建立一个Spring的配置文件bean5.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:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <bean id="student1" class="org.westos.entity.Student" p:studentName="张三" p:studentNo="716217255"/> <bean id="student12" class="org.westos.entity.Student" p:studentName="李四" p:studentNo="1276312t"/> <!--如果需要提取集合作为公共部分,需要引入util命名空间--> <util:list id="students"> <ref bean="student1"/> <ref bean="student12"/> </util:list> <bean id="collectionDemo2" class="org.westos.entity.CollectionDemo2"> <property name="list" ref="students"/> </bean> </beans>测试
@Test public void test2() { //测试util命名空间提取集合 ApplicationContext context = new ClassPathXmlApplicationContext("bean5.xml"); CollectionDemo2 demo2 = (CollectionDemo2) context.getBean("collectionDemo2"); System.out.println(demo2.getList()); //Student无参构造执行了 //Student无参构造执行了 //[Student{studentNo='716217255', studentName='张三'}, Student{studentNo='1276312t', studentName='李四'}] }在Spring中存在两种类型的Bean
普通bean工厂bean区别:普通Bean,定义什么类型,就返回什么类型;工厂bean,定义的类型可以和返回的类型不一致。
1、创建一个类,作为工厂bean,实现接口FactoryBean;
public class FactoryBeanDemo implements FactoryBean<Student> { @Override public Student getObject() throws Exception { Student student = new Student(); student.setStudentName("田七"); student.setStudentNo("716238127"); return student; } @Override public Class<?> getObjectType() { return null; } @Override public boolean isSingleton() { return false; } }为了不和上面的冲突,重新建立一个Spring的配置文件bean6.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"> <bean id="factoryBeanDemo" class="org.westos.entity.FactoryBeanDemo"> </bean> </beans>测试
@Test public void test1() { ApplicationContext context = new ClassPathXmlApplicationContext("bean6.xml"); Student student = (Student) context.getBean("factoryBeanDemo"); System.out.println(student); //Student无参构造执行了 //Student{studentNo='716238127', studentName='田七'} }为了不和上面的冲突,重新建立一个Spring的配置文件bean7.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"> <bean id="s" class="org.westos.entity.Student"> <property name="studentNo" value="273182763"/> <property name="studentName" value="王霸"/> </bean> </beans>测试
@Test public void test1() { //测试默认的bean是单实例对象 ApplicationContext context = new ClassPathXmlApplicationContext("bean7.xml"); Student s1 = (Student) context.getBean("s"); Student s2 = (Student) context.getBean("s"); System.out.println(s1 == s2); //Student无参构造执行了 //true }那么如何设置单实例还是多实例?
(1)在Spring配置文件的bean标签中存在属性scope用于设置单实例还是多实例;
(2)scope属性可用值有多个,常用的有两个;
singletonprototyperequestsession(3)singleton,默认
(4)prototype,多实例对象。
修改bean7.xml文件,scope属性设置为prototype;
<?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"> <bean id="s" class="org.westos.entity.Student" scope="prototype"> <property name="studentNo" value="273182763"/> <property name="studentName" value="王霸"/> </bean> </beans>重新测试:
@Test public void test1() { //测试默认的bean是单实例对象 ApplicationContext context = new ClassPathXmlApplicationContext("bean7.xml"); Student s1 = (Student) context.getBean("s"); Student s2 = (Student) context.getBean("s"); System.out.println(s1 == s2); //Student无参构造执行了 //Student无参构造执行了 //false }执行了两次构造方法,是两个对象。
区别:
singleton单实例,prototype多实例;singleton,加载spring配置文件时,创建单实例对象到Spring容器;prototype,当你第一次使用时,创建对象。生命周期:从对象创建到对象销毁的过程。
通过构造器创建bean实例(无参构造);为bean的属性设置值和对其他bean的引用(set方法);调用bean的初始化的方法(需要进行配置初始化的方法);bean可以使用了;当容器关闭的时候,调用bean的销毁的方法(需要进行配置销毁的方法); public class User { private String name; public User() { System.out.println("第一步,User类的无参构造执行了"); } public void setName(String name) { System.out.println("第二步,User类的setName方法执行了"); this.name = name; } public void initMethod() { System.out.println("第三步,User类的初始化方法执行了"); } public void destroyMethod() { System.out.println("第五步,User类的销毁方法执行了"); } }为了不和上面的冲突,重新建立一个Spring的配置文件bean8.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"> <bean id="user" class="org.westos.entity.User" init-method="initMethod" destroy-method="destroyMethod"> <property name="name" value="kid"/> </bean> </beans>测试
@Test public void test2() { //测试Bean的生命周期方法 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean8.xml"); User user = (User) context.getBean("user"); System.out.println("第四步,获取到了User对象,可以使用了," + user); //手动销毁Bean实例,调用destroy方法 context.close(); } 第一步,User类的无参构造执行了 第二步,User类的setName方法执行了 第三步,User类的初始化方法执行了 第四步,获取到了User对象,可以使用了,org.westos.entity.User@ed9d034 第五步,User类的销毁方法执行了如果加上Bean的后置处理器,那么生命周期会变为7步,[在执行完set方法后,把bean实例传递给下面的两个方法]。
BeanPostProcessor接口:bean的后置处理器 postProcessBeforeInitialization():在初始化方法调用之前(initMethod/afterPropertiesSet方法/@PostConstruct)工作 postProcessAfterInitialization():在初始化方法调用之后工作
演示添加后置处理器,
public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization..." + beanName + "->" + bean); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization..." + beanName + "->" + bean); return bean; } }将MyBeanPostProcessor注册到Spring容器,为当前配置文件中的bean设置后置处理器。
<?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"> <bean id="user" class="org.westos.entity.User" init-method="initMethod" destroy-method="destroyMethod"> <property name="name" value="kid"/> </bean> <!-- 配置后置处理器 --> <bean id="myBeanPostProcessor" class="org.westos.entity.MyBeanPostProcessor"> </bean> </beans>重新测试
第一步,User类的无参构造执行了 第二步,User类的setName方法执行了 postProcessBeforeInitialization...user->org.westos.entity.User@587d1d39 第三步,User类的初始化方法执行了 postProcessAfterInitialization...user->org.westos.entity.User@587d1d39 第四步,获取到了User对象,可以使用了,org.westos.entity.User@587d1d39 第五步,User类的销毁方法执行了我们上面的property标签,都是属于手动配置哪个属性设置哪个值,哪个bean。(手动装配)
自动装配:根据你指定的装配规则(属性名称、属性类型),Spring会自动将匹配到的属性值自动进行注入。
为了不和上面的冲突,重新建立一个Spring的配置文件bean9.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"> <bean id="studentDao" class="org.westos.dao.StudentDaoImpl"> </bean> <bean id="studentServiceDemo" class="org.westos.service.StudentService" autowire="byType"> </bean> </beans> @Test public void test1() { //测试自动注入 ApplicationContext context = new ClassPathXmlApplicationContext("bean9.xml"); StudentService studentService = (StudentService) context.getBean("studentServiceDemo"); StudentDaoImpl impl = (StudentDaoImpl) context.getBean("studentDao"); System.out.println(studentService.getStudentDao() == impl); //true }常用的autowired值,byType和byName。
如果是byName,那么需要bean的id和属性值一致。
如果是byType,那么容器中只能有一种类型的bean。
在实际中一般是用注解开发。
当需要配置数据库相关信息时,比如配置数据库连接池Druid,
首先需要把jar包引入到模块中;
<artifactId>spring-02</artifactId> <dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.23</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> </dependencies>为了不和上面的冲突,重新建立一个Spring的配置文件bean10.xml。
1、直接在bean.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"> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///mybatis?useSSL=false"/> <property name="username" value="root"/> <property name="password" value="995995zxvc"/> </bean> </beans>2、引入外部属性文件;
首先引入context名称空间。
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql:///mybatis?useSSL=false jdbc.username=root jdbc.password=995995zxvc <?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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:property-placeholder location="jdbc.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> </beans>测试
@Test public void test1() throws SQLException { //测试获取数据库连接 ApplicationContext context = new ClassPathXmlApplicationContext("bean10.xml"); DruidDataSource druidDataSource = (DruidDataSource) context.getBean("dataSource"); System.out.println(druidDataSource.getConnection()); //com.mysql.jdbc.JDBC4Connection@482cd91f }为了方便起见,重新建立一个模块spring-03来学校注解的Bean管理。
Spring针对Bean管理中创建对象提供的注解:
@Component@Service@Controller@Repository上面四个注解的功能类似,都可以用来创建Bean实例。
如果使用注解创建对象,那么必须要开启组件扫描。[首先引入context命名空间]
<?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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "> <!--开启组件扫描 1、如果扫描多个包,多个包使用逗号隔开; 2、base-package可以扫描包的上层目录--> <context:component-scan base-package="org.westos"/> </beans> @Service(value = "userService") //Bean的默认id为类名称,首字母小写 public class UserService { public void add() { System.out.println("serviceAdd"); } }测试
@Test public void test() { //测试@Service + context:component-scan标签 ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); UserService userService = (UserService) context.getBean("userService"); userService.add(); //serviceAdd }@Autowired:根据属性的类型自动装入;【@Autowired不需要有setXxx方法】
@Service public class UserService { @Autowired private UserMapper userMapper; public void add() { userMapper.add(); System.out.println("serviceAdd"); } } @Repository public class UserMapper { public void add() { System.out.println("mapper add"); } }@Qualifier:根据名称注入;
现在这个注解必须和@Autowired配合使用。
当你存在多个UserMapper对象时,@Autowired就无法注入。
@Service public class UserService { @Autowired @Qualifier(value = "userMapper1") private UserMapper userMapper; public void add() { userMapper.add(); System.out.println("serviceAdd"); } } <?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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "> <!--开启组件扫描 1、如果扫描多个包,多个包使用逗号隔开; 2、base-package可以扫描包的上层目录--> <context:component-scan base-package="org.westos"/> <bean id="userMapper1" class="org.westos.mapper.UserMapper"/> </beans>容器中存在多个UserMapper的实现类。
@Resource:可以根据类型,也可以根据名称;
默认按照属性名称进行装配,修改name属性可以指定要装配的beanJava包中的注解,并不是Spring官方提供的注解。
@Service public class UserService { @Resource(name = "userMapper1") private UserMapper userMapper; public void add() { userMapper.add(); System.out.println("serviceAdd"); } }@Value:注入普通类型;
@Value("张三") private String name;创建配置类,替代xml配置文件。
@Configuration @ComponentScan(basePackages = {"org.westos"}) public class SpringConfig { //作为配置类,替代xml配置文件 }有了配置类,就不需要bean.xml配置文件了。
@Test public void test2() { //测试完全注解开发 ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); UserService userService = (UserService) context.getBean("userService"); userService.add(); //mapper add //serviceAdd }