Spring是一个框架,也是一个容器,其核心技术是IOC、AOP,实现程序的解耦合或者是尽可能减少耦合。在Spring容器中存放的是各种Java对象,容器可以完成对象的创建、对象之间关系的管理。开发中使用的Dao类、Service类、Controller类、工具类等可以放入容器中,而实体类或者需要由其他容器管理的对象如由tomcat管理的Servlet、Filter、Listener等不需要放在Spring容器中。 IOC(Inversion of Control)是一个概念,是一种思想,将传统上由程序代码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理。控制反转就是对对象控制权的转移,从程序代码本身反转到了外部容器,通过容器实现对象的创建,属性赋值, 依赖的管理。 IOC技术的具体实现使用的的是依赖注入。DI(Dependency Injection),程序代码不做定位查询,这些工作由容器自行完成。Spring使用DI的技术,底层靠的是反射机制。 DI给属性赋值的方式有构造函数注入和set注入。构造函数注入是Spring调用有参构造方法,set注入是Spring调用类 的set方法实现属性赋值。 前面介绍的都是文字概念,下面具体介绍一下相关的知识。 首先,前面说到在Spring容器中存放的是各种Java对象,容器可以完成对象的创建,那么Spring是怎么完成对象的创建的呢?在Spring中,Java对象称之为bean。
可以通过bean标签下的scope改变bean对象的作用域:
赋的什么值:
value:基本数据类型+String
ref:引用其他的bean
构造函数注入必须有有参构造函数,必须注入数据,不管用不用得到,改变了Bean实例化对象的方式,不能使用默认的无参构造了。在类中要写有参构造方法。实际开发中一般不用这种方法。 接着介绍set注入方法。
是配置文件的根标签,在这个标签下进行Java对象的创建。 创建对象即实例化Bean,在Spring中有三种方式:使用默认无参构造方法创建对象、使用实例工厂的方法创建对象、使用静态工厂的方法创建对象。最常用的是使用默认无参构造方法创建对象。如下代码所示:
一个bean标签声明一个对象,上面的代码等价于:Someservice someservice=new SomeserviceImpl();
Spring把创建好的对象放进Map集合中:
(“someservice”:对象)(“someservice1”:对象)
使用的时候根据id这个唯一的key就可以获取对象。
getBean("someservice");
bean标签中有以下细节:
id:自定义的对象名称,要求是唯一值, 表示在Spring中的对象名称,通过这个名称可以从Spring中找到对象,获取对象。 class:类的全限定名称,不能是接口(Spring使用反射创建对象);class可以是非自定义的对象,如java.util.Date也可以用Spring创建对象。 scope:指定bean对象的作用域(对象的存在范围和可见性)。
DI给属性赋值的方式有构造函数注入和set注入。注入的意思就是给属性赋值。首先看构造函数注入:package org.zhu.service.impl;import java.util.Date;public class Student { private String name; private int age; private Date birthday; public Student(String name, int age, Date birthday) { this.name = name; this.age = age; this.birthday = birthday; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", birthday=" + birthday + '}'; }}
<?xml version="1.0" encoding="UTF-8"?> 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">
@Test public void test3(){ String config="applicationContext.xml"; ApplicationContext ac=new ClassPathXmlApplicationContext(config); Student mystudent = (Student) ac.getBean("mystudent"); System.out.println(mystudent); }
找给谁赋值:
index:参数在构造函数中的索引位置,从0开始。
type:参数在构造函数中的数据类型。
name:参数在构造函数中的名字。赋的什么值:
value:基本数据类型+String
ref:引用其他的bean
构造函数注入必须有有参构造函数,必须注入数据,不管用不用得到,改变了Bean实例化对象的方式,不能使用默认的无参构造了。在类中要写有参构造方法。实际开发中一般不用这种方法。 接着介绍set注入方法。
public class Student { private String name; private Address address; private String[] books; private List hobbies; private Map card; private Set games; private String wife; private Properties info; public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String[] getBooks() { return books; } public void setBooks(String[] books) { this.books = books; } public List getHobbies() { return hobbies; } public void setHobbies(List hobbies) { this.hobbies = hobbies; } public Map getCard() { return card; } public void setCard(Map card) { this.card = card; } public Set getGames() { return games; } public void setGames(Set games) { this.games = games; } public String getWife() { return wife; } public void setWife(String wife) { this.wife = wife; } public Properties getInfo() { return info; } public void setInfo(Properties info) { this.info = info; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", address=" + address.getAddress() + ", books=" + Arrays.toString(books) + ", hobbies=" + hobbies + ", card=" + card + ", games=" + games + ", wife='" + wife + '\'' + ", info=" + info + '}'; }}
public class Address { private String address; public String getAddress() { return address; } public void setAddress(String address) { this.address = address; }}
<?xml version="1.0" encoding="UTF-8"?> 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"> 西游记 红楼梦 三国演义 水浒传 唱 跳 Rap 篮球 LOL 王者农药 和平精英 119110022293 621456879
public class testtt { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); Student stu = (Student) context.getBean("stu"); System.out.println(stu.toString()); }}
Student{name='zhulin', address=清水, books=[西游记, 红楼梦, 三国演义, 水浒传], hobbies=[唱, 跳, Rap, 篮球], card={姓名=朱琳, 学号=119110022293}, games=[LOL, 王者农药, 和平精英], wife='null', info={学号=119110022293, 银行卡号=621456879}}
此外还有p命名空间注入、p命名空间注入,本质都是set注入方式。 P命名空间注入 : 需要在头文件中加入约束文件:导入约束 : xmlns:p="http://www.springframework.org/schema/p"
c 命名空间注入 : 需要在头文件中加入约束文件:导入约束 : xmlns:c="http://www.springframework.org/schema/c"
在上面的代码中,ApplicationContext即表示Spring容器,通过容器获取对象,它是BeanFactory的子接口,BeanFactory是Spring容器的顶层接口。ApplicationContext 用来获取加载配置文件,使用ApplicationContext接口,只要一读取配置文件,默认情况下就会创建对象,而BeanFactory是什么时候使用对象什么时候创建。ClassPathXmlApplicationContext是ApplicationContext接口的实现类,它从类的根路径下加载配置文件。此外,还有: FileSystemXmlApplicationContext:从磁盘路径加载配置文件 AnnotationConfigApplicationContext:使用注解配置容器对象 这两个实现类。 对于引用类型,Spring框架可以根据某些规则给其赋值,常见的规则是: byName:根据名称自动注入byType:根据类型自动注入
当配置文件中被调用者 bean 的 id 值与代码中调用者 bean 类的属性名相同时,可使用 byName 方式,让容器自动将被调用者 bean 注入给调用者 bean。容器是通过调用者的bean类的属性名与配置文件的被调用者 bean的id进行比较而实现自动注入的。例如,在Student类中,School类型的属性名是”school“,那么在xml配置文件中:<?xml version="1.0" encoding="UTF-8"?> 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">
使用 byType 方式自动注入,要求配置文件中被调用者 bean 的 class 属性指定的类, 要与代码中调用者 bean 类的某引用类型属性类型同源。即要么相同,要么有 is-a 关系(子 类,或是实现类)。但这样的同源的被调用 bean 只能有一个。多于一个,容器就不知该匹配 哪一个了,会报异常:NoUniqueBeanDefinitionException
<?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="myStudent" class="com.zhu.Student" autowire="byType"> <property name="name" value="周武" /> <property name="age" value="22"/> bean> <bean id="mySchool" class="com.bjpowernode.School"> <property name="name" value="清华大学" /> <property name="address" value="北京的海淀区" /> bean> beans>
此外,还可以使用注解实现自动装配: @Autowires:默认ByType,实体类可以去掉set方法,xml可以省略id。 @Qualifier(value=“cat”) 根据类型自动装配,加上@Qualifier则可以根据byName的方式自动装配。
@Autowired @Qualifier(value="cat11") private Cat cat; @Autowired @Qualifier(value="dog22") private Dog dog; private String str;
@Resource :先ByName再ByType它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。在下面的注解知识部分还会介绍这几个注解的用法。
最后,介绍关于使用注解开发的知识。想要使用注解形式,必须得要引入aop的包,在配置文件当中,还得要引入一个context约束。<?xml version="1.0" encoding="UTF-8"?> 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:component是声明组件扫描器,指定注解所在的包名,让框架找到注解,base-package指定注解在项目中的包名,框架会扫描这个包和子包中所有类的注解,按照注解的功能,创建对象,赋值属性。
首先看第一个注解@Component,用来创建对象,通过类的无参构造方法,同一样。@Component(value="mystudent1")public class Student { @Value("张三") private String name; private int age; private Date birthday; public Student() { } public Student(String name, int age, Date birthday) { this.name = name; this.age = age; this.birthday = birthday; } public void setName(String name) { this.name = name; } @Value("18") public void setAge(int age) { this.age = age; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", birthday=" + birthday + '}'; }}
value可以省略,也可以在@Component后什么都不写,默认的对象名是类名首字母变成小写,此外,@Component还有三个衍生注解:@Repository :用于对 DAO 实现类进行注解 @Service :用于对 Service 实现类进行注解 @Controller: 用于对Controller实现类进行注解这三个注解与@Component 都可以创建对象,但这三个注解还有其他的含义,@Service 创建业务层对象,业务层对象可以加入事务功能,@Controller 注解创建的对象可以作为处理器接收用户的请求。它们可以给项目分层。
接着看第五个注解@Value。@Value给简单类型的属性赋值。value 是String类型的,表示简单类型的属性值,它的位置可以在属性定义的上面, 无需set方法,是常用的方式 ,也可以在set方法上面。 第六个注解@Autowired,@Autowired给引用类型赋值,默认按byType注入,在@Autowired的基础上,再加入@Qualifier可以按照byName注入。@Qualifier在给引用属性注入时不能单独使用,但在给方法参数注入时可以单独使用。 这里有个注意点,@Autowired默认情况下要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) 。第八个注解@Resource ,@Resource默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
前面已经说过,@Autowired和@Resource作用相同,都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。
最后,总结一下XML和注解。XML可以适用任何场景 ,结构清晰,配置和代码是分离的,在 xml 中做修改,无需编译代码,只需重启服务器即可将新的配置加载。但是其编写麻烦,效率低,大型项目过于复杂。注解不是自己提供的类使用不了,开发简单、方便、直观、高效,代码少,没有配置文件的书写那么复杂,但是它以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码的。在实际开发中将两种方式结合起来,能用注解的用注解,不能用注解的用XML。版权声明:本文为weixin_32059007原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。