所谓的框架其实就是程序的架子,在这个程序的架子中,搭建起程序的基本的骨架,针对程序的通用问题给出了便捷的解决方案,可以使开发人员 基于框架快速开发具体的应用程序。
常见的框架
SSH: Struts2 (Web层) / Spring (Service层) / Hibernate (DAO层)
SSM: SpringMVC (Web层) / Spring (Service层) / MyBatis (DAO层)
Spring是一个Service层的框架,可以整合许多其它框架进行工作。
Spring的主要技术是 IoC (DI) & AoP
IoC称之为控制反转,简单来说就是将对象的创建的权利及对象的生命周期的管理过程交由Spring框架来处理
开发过程中不再需要关注对象的创建和生命周期的管理,而是在需要时由Spring框架提供,这个由spring框架管理对象创建和生命周期的机制称之为控制反转
通过IoC + 接口,可以在软件分层实践中,将耦合性提取到Spring容器中进行管理。这样就可以实现软件分层中“高内聚,低耦合”目标中的低耦合了
入门案例演示:
创建项目:创建基本的java项目
创建配置文件 — applicationContext.xml 放置到源码目录下
<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">
beans>
在Idea中: 在src目录下右键 — >新建 — > XML Configuration File —> Spring Config
开发代码
创建一个类:
public class Person01 {
public void eat(){
System.out.println("eat ... ");
}
public void say(){
System.out.println("say ... ");
}
}
配置bean:
<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="person01" class="cn.zss.domain.Person01">bean>
beans>
在程序中通过Spring容器获取对象并使用:
public class Test01 {
/*
* 普通方法创建对象
* */
@Test
public void test01(){
Person01 person01 = new Person01();
person01.say();
person01.eat();
}
/*
* Spring框架创建对象
* */
@Test
public void test02(){
// 1. 初始化Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2. 通过Spring容器获取对象
Person01 p = (Person01) context.getBean("person01");
// 3. 适用对象
p.eat();
p.say();
// 4.关闭容器
((ClassPathXmlApplicationContext) context).close();
}
}
getBean
方法来从容器中获取对象时,其实就是根据传入的条件在内置的Map中寻找是否有匹配的键值,如果有则将该键值对中保存的对象返回,如果没有匹配到则抛出异常。推论:
默认情况下,多次获取同一个id的bean,得到的将是同一个对象。
不可以配置多个id相同的bean
可以配置多个id不同但class相同的bean
/*
* SpringIOC推论1:
* 默认情况下,从Spring容器中多次获取同一个id的bean得到的同一个对象
* 原因在于:从Spring容器中获取bean的过程本质上是从容器内部map中找到指定键的值返回
* 无论获取多少次,得到的都是map中key对应的对象,自然是同一个对象
* */
/*
* SpringIOC推论2:
* 不可以在spring容器中配置多个id相同的bean
* 原因在于:向spring容器中注册的bean,本质上要以指定的id和反射创建的对象形成键值对存储到map中
* 而map的键是不允许重复的,所以配置多个id相同的bean无法同时存入内部map,因此会抛出异常
* */
@Test
public void test03(){
// 初始化容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取 bean
Person01 p1 = (Person01) context.getBean("person01");
// 第二次获取person01
Person01 p2 = (Person01) context.getBean("person01");
System.out.println(p1 == p2); // true
}
/*
* SpringIOC推论3:
* 可以在容器中配置多个id不同但是class相同的bean
* 原因在于:多个class相同的bean,分别反射创建对象后,使用自己的id存储到spring容器内的map中,因此可以在spring中配置多个class相同但是id不同的bean
* */
@Test
public void test04(){
// 初始化容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取 bean
Person01 p1 = (Person01) context.getBean("person01");
// 获取第二个bean
Person01 p2 = (Person01) context.getBean("person01x");
System.out.println(p1 == p2); // false
}
通过context.getBean()方法获取bean时,可以通过如下两种方式获取:
传入id值
/*
* Spring容器获取对象的方法1:通过id获取
* 如果找不到:抛出异常[NoSuchBeanDefinitionException]
* 如果找到唯一的一个:返回找到的对象
* 如果找到多个 (推论2):容器初始化时,抛出异常[BeanDefinitionParsingException]
* */
@Test
public void test01(){
// 1. 初始化Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2. 通过容器获取bean
Person01 p1 = (Person01) context.getBean("person01");
// 3. 使用bean
p1.eat();
p1.say();
// 4. 关闭spring容器
((ClassPathXmlApplicationContext) context).close();
}
传入class类型
<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="person01" class="cn.zss.domain.Person01">bean>
<bean id="person02" class="cn.zss.domain.Person01">bean>
beans>
/*
* Spring容器获取对象的方法2:通过class获取
* 如果找不到:抛出异常[NoSuchBeanDefinitionException]
* 如果找到唯一的一个:返回找到的对象
* 如果找到多个:在获取bean时,抛出异常[NoUniqueBeanDefinitionException]
* */
@Test
public void test02(){
// 1. 初始化Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2. 通过容器获取bean
Person01 p1 = context.getBean(Person01.class);
// 3. 使用bean
p1.say();
p1.eat();
// 4. 关闭spring容器
((ClassPathXmlApplicationContext) context).close();
}
通过class方式获取bean时,如果同一个类配置过多个bean,则在获取时因为无法确定到底要获取哪个bean会抛出异常。
SpringIOC在通过class获取bean时,如果找不到该类型的bean还会去检查是否存在该类型的子孙类型的bean,如果有则返回,如果找不到或找到多个则抛出异常。这符合java面向对象思想中的多态的特性。
在 Spring中提供了别名标签
<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="person01" class="cn.zss.domain.Person01">bean>
<alias name="person01" alias="per01">alias>
beans>
public class Test01 {
@Test
public void test01(){
// 1. 初始化Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2. 通过容器获取bean
Person01 p1 = (Person01) context.getBean("person01");
// 通过别名获取bean
Person01 p2 = (Person01) context.getBean("per01");
// 3. 使用bean
System.out.println(p1 == p2); // true
// 4. 关闭spring容器
((ClassPathXmlApplicationContext) context).close();
}
}
通过类的无参构造方法创建对象
当用最普通方式配置一个
时,默认就是采用类的无参构造创建对象。
在Spring容器初始化时,通过
上配置的class属性反射得到字节码对象,通过newInstance()创建对象
这种方式下spring创建对象,要求类必须有无参的构造,否则无法通过反射创建对象,会抛出异常。
public class Person01 {
private int age;
Person01(int age){
this.age = age;
}
public void eat(){
System.out.println("eat ... ");
}
}
public class Test01 {
@Test
/*
* 普通方法创建对象
* */
public void test01(){
Person01 person01 = new Person01(5);
person01.eat();
}
/*
* 通过反射创建对象
* newInstance()方法本质上是在调用当前类的无参构造器创建对象
* 如果该类没有无参构造器,则此方法无法正常执行,会抛出异常
* */
@Test
public void test02() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class clz = Class.forName("cn.zss.domain.Person01");
// 前提:类必须有无参构造函数
Person01 p = (Person01) clz.newInstance();
p.eat();
}
/*
* 如果bean没有无参构造,spring无法通过默认的机制管理此bean
* */
@Test
public void test03() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person01 p = (Person01)context.getBean("person01");
p.eat();
((ClassPathXmlApplicationContext)context).close();
}
}
通过静态工厂创建对象
工厂设计模式 (Factory Pattern)
很多的时候,我们面对的类是无法通过无参构造去创建的,例如该类没有无参构造、是一抽象类等等情况,此时无法要求spring通过无参构造创建对象,此时可以使用静态工厂方式创建对象。
定义Person类
public class Person01 {
private String name;
private int age;
private char gender;
public Person01(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
}
定义Person类的静态工厂
/*
* 静态工厂
* */
public class Person01StaticFactory {
// 私有化构造方法,保证静态工厂类无法实例化
private Person01StaticFactory(){}
// 提供公有静态方法用来生产目标对象
public static Person01 getInstance(){
return new Person01("lili",20,'女');
}
}
编写配置文件
<!-- 静态工厂配置-->
<bean id="person01" class="cn.zss.domain.Person01StaticFactory" factory-method="getInstance"></bean>
创建对象
public class Test01 {
@Test
public void test01(){
// 1. 初始化容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2. 获取bean
Person01 p = (Person01) context.getBean("person01");
// 3. 使用bean
System.out.println(p);
// 4. 关闭容器
((ClassPathXmlApplicationContext)context).close();
}
}
实例工厂创建对象
实例工厂也可以解决类是无法通过无参构造创建的问题,解决的思路和静态工厂类似,只不过实例工厂提供的方法不是静态的。
spring需要先创建出实例工厂的对象,再调用实例工厂对象上指定的普通方法来创建对象。所以实例工厂也需要配置到Spring中管理。
定义Person类的实例工厂
public class Person01InstanceFactory {
public Person01 getInstance(){
return new Person01("Tom",20,'男');
}
}
编写配置文件
<bean id = "pif" class="cn.zss.domain.Person01InstanceFactory">bean>
<bean id = "person01" factory-bean="pif" factory-method="getInstance">bean>
创建对象
@Test
public void test02(){
// 1. 初始化容器
ApplicationContext context = new ClassPathXmlApplicationContext("application2Context.xml");
// 2. 获取bean
Person01 p = (Person01) context.getBean("person01");
// 3. 使用bean
System.out.println(p);
// 4. 关闭容器
((ClassPathXmlApplicationContext)context).close();
}
Spring工厂创建对象
定义Person类的Spring工厂
/*Spring工厂*/
public class Person01SpringFactory implements FactoryBean<Person01> {
/*
* 生产对象的方法
* */
@Override
public Person01 getObject() throws Exception {
return new Person01("Potter",20,'男');
}
/*
* 获取当前工厂生产的对象类型的方法
* */
@Override
public Class<?> getObjectType() {
return Person01.class;
}
/*
* 当前对象是否是单例对象
* */
@Override
public boolean isSingleton() {
return true;
}
}
编写配置文件
<bean id = "person01" class="cn.zss.domain.Person01SpringFactory">bean>
创建对象
@Test
public void test02(){
// 1. 初始化容器
ApplicationContext context = new ClassPathXmlApplicationContext("application3Context.xml");
// 2. 获取bean
Person01 p = (Person01) context.getBean("person01");
// 3. 使用bean
System.out.println(p);
// 4. 关闭容器
((ClassPathXmlApplicationContext)context).close();
}
Spring容器管理的bean在默认情况下是单例的 (常用),即一个bean只会创建一个对象,存在内置 map中,之后无论获取多少次该bean,都返回同一个对象。
Spring默认采用单例方式,减少了对象的创建,从而减少了内存的消耗。
在实际开发中是存在多例的需求的,Spring也提供了选项可以将bean设置为多例模式。
配置单例模式 / 多例模式:
<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="cart" class="cn.zss.domain.Cart" scope="prototype">bean>
beans>
bean在单例模式下的生命周期:
bean在多例模式下的生命周期:
Spring默认会在容器初始化的过程中,解析xml,并将单例的bean创建并保存到map中
这样的机制在bean比较少时问题不大,但一旦bean非常多时,spring需要在启动的过程中花费大量的时间来创建bean,花费大量的空间存储bean,但这些bean可能很久都用不上,在时间和空间上的浪费显得非常的不值得。
所以Spring提供了懒加载机制。所谓的懒加载机制就是可以规定指定的bean不在启动时立即创建,而是在后续第一次用到时才创建,从而减轻在启动过程中对时间和内存的消耗。
懒加载机制只对单例bean有作用,对于多例bean设置懒加载没有意义。
懒加载的配置方式:
<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"
default-lazy-init="true">
<bean id="person" class="cn.zss.domain.Person" lazy-init="true">bean>
beans>
如果同时设定全局和指定bean的懒加载机制,且配置不相同,则对于该bean局部配置覆盖全局配置。
在Spring中如果某个bean在初始化之后或销毁之前需要做一些额外操作可以为该bean配置初始化和销毁的方法,在这些方法中完成要功能。
配置方式 (示例):
定义类
public class JDBCUtils {
/*
* 初始化方法
* */
public void init(){
System.out.println("连接数据库");
}
/*
* 销毁方法
* */
public void destroy(){
System.out.println("销毁数据库连接");
}
/*
* 普通方法
* */
public void getConn(){
System.out.println("获取连接");
}
}
编写配置文件
<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="jdbcUtils" class="cn.zss.domain.JDBCUtils" init-method="init" destroy-method="destroy">
bean>
beans>
测试
public class Test01 {
/*
* 初始化,销毁方法测试
* */
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
JDBCUtils jdbcUtils = (JDBCUtils) context.getBean("jdbcUtils");
jdbcUtils.getConn();
/*
* 打印结果:
* 连接数据库 获取连接 销毁数据库连接
* */
((ClassPathXmlApplicationContext)context).close();
}
}
Spring中关键方法的执行顺序:
创建对象的过程中Spring可以依据配置对对象的属性进行设置,这个过称之为依赖注入,即DI
通常的javabean属性都会私有化,而对外暴露Getter和Setter方法,此时spring可以通过Setter方法将属性的值注入对象。
普通属性注入:
a. 定义类
public class Hero {
private String name;
private int age;
private List<String> job;
private Set<String> set;
private Map<String, String> map;
private Properties props;
public Hero() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<String> getJob() {
return job;
}
public void setJob(List<String> job) {
this.job = job;
}
public Set<String> getSet() {
return set;
}
public void setSet(Set<String> set) {
this.set = set;
}
public Map<String, String> getMap() {
return map;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public Properties getProps() {
return props;
}
public void setProps(Properties props) {
this.props = props;
}
@Override
public String toString() {
return "Hero{" +
"name='" + name + '\'' +
", age=" + age +
", job=" + job +
", set=" + set +
", map=" + map +
", props=" + props +
'}';
}
}
b. 编写配置文件
<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="hero" class="cn.zss.domain.Hero">
<property name="name" value="狄仁杰"> property>
<property name="age" value="18">property>
<property name="job">
<list>
<value>神探value>
<value>官员value>
list>
property>
<property name="set">
<set>
<value>s1value>
<value>s2value>
set>
property>
<property name="map">
<map>
<entry key="k1" value="v1">entry>
<entry key="k2" value="v2">entry>
<entry key="k2" value="v4">entry>
map>
property>
<property name="props">
<props>
<prop key="p1">v1prop>
<prop key="p2">v2prop>
props>
property>
bean>
beans>
自定义bean的注入:
a. 自定义类
public class Enemy {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Enemy{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
b. 在Hero类中定义属性并提供get和set方法
public class Hero {
private Enemy enemy;
// ... 其他属性
public Enemy getEnemy() {
return enemy;
}
public void setEnemy(Enemy enemy) {
this.enemy = enemy;
}
// ... 其他get和set方法
@Override
public String toString() {
return "enemy=" + enemy;
}
}
c. 编写配置文件
<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="hero" class="cn.zss.domain.Hero">
<property name="enemy" ref="enemy">
property>
bean>
<bean id = "enemy" class="cn.zss.domain.Enemy">
<property name="name" value="袁天罡">
property>
<property name="age" value="20">
property>
bean>
beans>
自动装配
为指定
?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="hero" class="cn.zss.domain.Hero" autowire="byName">
<bean id = "enemy" class="cn.zss.domain.Enemy">
<property name="name" value="袁天罡">
property>
<property name="age" value="20">
property>
bean>
beans>
对象属性设置的另一种方式是在对象创建的过程中通过构造方法传入并设置对象的属性;Spring也可以通过这样的构造方法实现属性的注入
a. 定义类
public class Hero {
String name;
private int age;
private Enemy enemy;
public Hero() {
}
public Hero(String name, int age, Enemy enemy) {
this.name = name;
this.age = age;
this.enemy = enemy;
}
@Override
public String toString() {
return "Hero{" +
"name='" + name + '\'' +
", age=" + age +
", enemy=" + enemy +
'}';
}
}
public class Enemy {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Enemy{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
b. 编写配置文件
<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="hero" class="cn.zss.domain.Hero" >
<constructor-arg index="0" value ="狄仁杰" type="java.lang.String">constructor-arg>
<constructor-arg index="1" value ="45" type="int">constructor-arg>
<constructor-arg index="2" type="cn.zss.domain.Enemy" ref="enemy">constructor-arg>
bean>
<bean id ="enemy" class="cn.zss.domain.Enemy">
<property name="name" value="袁天罡">property>
<property name="age" value="66">property>
bean>
beans>
c. 编写测试类
ublic class Test01 {
@Test
public void test01(){
// 初始化容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean
Hero hero = (Hero)context.getBean("hero");
// 使用bean
System.out.println(hero);
// 销毁bean
((ClassPathXmlApplicationContext)context).close();
}
}
注释:java中注释的格式://, /**/, /** */
注解:
注解在开发中,可以作为轻量化配置来使用,比起使用xml作为配置文件,更加的轻便易用,在java开发中大量的使用。
java 内置注解
@Override — 声明重写父类方法的注解,要求编译器帮我们检查是否成功的覆盖,如果没有成功覆盖父类方法,编译器将会进行报错提示。
@Deprecated — 声明方法被过时,不再建议使用,要求编译器在编译的过程中对于这样的方法的调用提出警告,提示方法过时。
@SuppressWarnings — 压制警告,提示编译器,在编译的过程中对指定类型的警告不再提示
注解可以基于有注解 / 没注解或者注解属性的不同来控制程序按照不同方式运行
注解常用作轻量化配置,替代配置文件的部分功能
注解方便开发阶段的配置和更改,配置文件在发布后仍可以方便修改,因此实际开发中注解和配置文件需要结合使用
开发一个注解类
使用元注解修饰注解的声明
@Target:用来声明被修饰的注解可以用在什么位置。
可以在@Target的属性中设置ElementType类型的数组来指定可以使用的位置。如果不用此元注解修饰,默认注解可以用在任意位置。
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface FirstAnno { // 自定义注解可以应用于属性和方法上
}
@Retention:用来声明被修饰的注解会被保留到什么阶段。
java —> 编译 —> .class —> 类加载器 —> 字节码
可以在该注解的属性中通过RetentionPolicy类型的值来指定注解被保留到何时。
RetentionPolicy.SOURCE:此注解将会被保留到源码阶段,.java中;在编译过程中被删除。这种类型的注解通常是给编译器看的。
RetentionPolicy.CLASS:此注解将会被保留在源码阶段和编译阶段,.java和.class中;在类加载的过程中被删除。这种类型的注解通常是给类加载器看的。
RetentionPolicy.RUNTIME:此注解将会被保留在源码阶段,编译阶段和运行阶段,.java .class和内存中的字节码中都会存在。这种类型的注解通常用来在运行阶段进行反射,控制程序运行过程。
只有RUNTIME级别的注解才可以通过反射技术进行反射。
@Documented :用来声明被修饰注解是否要被文档提取工具提取到文档中;javadoc命令可以用于生成文档
默认不提取。
@Inherited:用来声明被修饰的注解是否具有继承性
默认没有继承性
(属性名=属性值)
的方式 指定属性的值@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface FirstAnno {
public String name();
public int age() default 0;
String[] addrs();
}
public class Person {
String name;
int age;
@FirstAnno(name="lili",age=18, addrs={"china","beijing"})
public void eat(String food1, String food2){
System.out.println("eat...");
}
}
返回值 | 方法 |
---|---|
Annotation[] | getAnnotations ():返回此元素上存在的所有注释。 |
A | getAnnotation (Class annotationClass): 如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。 |
boolean | isAnnotationPresent (Class extends Annotation> annotationClass) : 如果指定类型的注释存在于此元素上,则返回 true,否则返回 false |
基本实现流程:
a. 导入开发包
b. 编写配置文件,并导入context约束
<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
">
beans>
Idea可以将该配置文件设置为模板,方便以后使用
文件 —> 设置 —> 编辑器 —> 文件和代码模板 —> 点击左侧加号新建模板
c. 开启包扫描
在配置文件中,开启包扫描,指定Spring自动扫描哪些个包下的类;只有在指定的扫描包下的类上的IOC注解才会生效。
<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:component-scan base-package="cn.zss.domain">context:component-scan>
beans>
d. 使用注解注册bean
在配置的包中的类上使用@Component注解,则这个类会自动被注册为bean
使用当前类的class为的class,通常情况下使用类名首字母小写为的id
如果类名的第二个字母为大写则首字母保留原样,如类名: PErson —> id名: PErson
也可以通过在@Component中配置value属性,明确的指定bean的id
package cn.zss.domain;
import org.springframework.stereotype.Component;
@Component //
/*@Component(value="per") 等价于 @Component("per")
*/
public class Person {
}
e. 测试类
public class Test01 {
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person p = (Person)context.getBean("person");
System.out.println(p);
((ClassPathXmlApplicationContext)context).close();
}
}
配置工厂类
配置工厂类中生产bean的方法
工厂中生产bean的方法要被@Bean修饰
则此方法会被SpringIOC调用,并将返回的对象注册为Spring的bean
默认自动推断id (根据方法名,不常用),在老版本中通过@Bean(name=“xxx”)指定id;在新版本中,通过value属性指定id。
案例演示:
a. 定义Dog类
package cn.zss.domain;
public class Dog {
public Dog (String name){
}
}
b. 定义Dog类的工厂类
package cn.zss.domain;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/*
* 实例工厂
* */
@Component
public class DogFactory {
//
@Bean(name = "dog")
//
public Dog getInstance(){
return new Dog("Tom");
}
}
c. 测试
@Test
public void test02(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Dog dog = (Dog)context.getBean("dog");
System.out.println(dog);
((ClassPathXmlApplicationContext)context).close();
}
a. 导入开发包
b. 编写配置文件
<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:component-scan base-package="cn.zss.domain"/>
<context:annotation-config/>
beans>
c. 注解方式注入spring内置支持的类型数据 - 非集合类型
package cn.zss.domain;
@Component
public class Hero {
@Value("美国队长")
private String name;
@Value("40")
private int age;
private List<String> list;
private Set<String> set;
private Map<String, String> map;
private Properties props;
@Override
public String toString() {
return "Hero{" +
"name='" + name + '\'' +
", age=" + age +
", list=" + list +
", set=" + set +
", map=" + map +
", props=" + props +
'}';
}
}
d. 编写properties配置文件(my.properties)并加载
myname = 美国队长
myage = 40
<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:component-scan base-package="cn.zss.domain">
context:component-scan>
<context:annotation-config>context:annotation-config>
<context:property-placeholder location="my.properties" />
beans>
e. 添加@Value注解
@Component
public class Hero {
@Value("${myname}")
private String name;
@Value("${myage}")
private int age;
private List<String> list;
private Set<String> set;
private Map<String, String> map;
private Properties props;
@Override
public String toString() {
return "Hero{" +
"name='" + name + '\'' +
", age=" + age +
", list=" + list +
", set=" + set +
", map=" + map +
", props=" + props +
'}';
}
}
f. 注解方式注入spring内置支持的类型数据
引入util名称空间,通过适当的util标签注册数据
<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:util="http://www.springframework.org/schema/util"
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
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
">
<context:component-scan base-package="cn.zss.domain">
context:component-scan>
<context:annotation-config>
context:annotation-config>
<context:property-placeholder location="my.properties" />
<util:list id="l1">
<value>l1value>
<value>l2value>
util:list>
<util:set id="s1">
<value>s1value>
<value>s2value>
util:set>
<util:map id="m1">
<entry key="k1" value="v1">entry>
<entry key="k2" value="v2">entry>
util:map>
<util:properties id ="p1">
<prop key="p1">v1prop>
<prop key="p2">v2prop>
util:properties>
beans>
再在类的属性中通过@Value注入赋值
@Component
public class Hero {
@Value("${myname}")
private String name;
@Value("${myage}")
private int age;
@Value("#{@l1}")
private List<String> list;
@Value("#{@s1}")
private Set<String> set;
@Value("#{@m1}")
private Map<String, String> map;
@Value("#{@p1}")
private Properties props;
@Override
public String toString() {
return "Hero{" +
"name='" + name + '\'' +
", age=" + age +
", list=" + list +
", set=" + set +
", map=" + map +
", props=" + props +
'}';
}
}
g. 使用注解注入自定义bean类型数据
在bean中的属性上通过@Autowired实现自定义bean类型的属性注入
当Spring容器解析到@Component注解时,创建当前类的bean在Spring容器中进行管理,在创建bean的过程中发现了@Autowired注解,会根据当前bean类型,寻找在Spring中是否存在该类型的bean,找到直接注入,如果找不到还会检查是否有子孙类、实现类存在,如果存在唯一的则自动注入,如果还是没有找到或找到多个无法注入,则还会按照属性名对应id去查找对应的bean,如果存在则注入,如果还是没有找到则抛出异常。
也可以额外配置@Qualifier(value=“xxx”)注解强制要求按照id寻找bean,则此时会直接使用给定的id寻找bean,而不会进行基于类型的匹配。
package cn.zss.domain;
@Component
public class Hero {
@Value("美国队长")
private String name;
@Value("100")
private int age;
/*首先按类型注入,
* 如果找到唯一就注入,
* 如果找不到或者找到多个,则开始按照id注入
* 寻找是否存在bean的id和当前属性的属性名相同,如果存在就注入,不存在就抛出异常
*/
@Autowired // 根据类型找到Enemy和newEnemy,然后根据id(enemy) 找到Enemy
// @Qualifier("newEnemy") --- > Hero{name='美国队长', age=100, enemy=Enemy{name='灭霸', age=150}}
// 一旦配置了@Qualifier,@Autowired的工作机制就会发生变化,直接按照指定的id进行注入,
// 如果找到唯一的就注入,找不到,或者找到多个直接抛出异常
private Enemy enemy;
@Override
public String toString() {
return "Hero{" +
"name='" + name + '\'' +
", age=" + age +
", enemy=" + enemy +
'}';
}
}
package cn.zss.domain;
@Component
public class Enemy {
@Value("九头蛇")
private String name;
@Value("100")
private int age;
@Override
public String toString() {
return "Enemy{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package cn.zss.domain;
@Component
public class NewEnemy extends Enemy{
@Value("灭霸")
private String name;
@Value("150")
private int age;
@Override
public String toString() {
return "Enemy{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
a. @Scope(value=“prototype”):配置修饰的类的bean是单例还是多例,如果不配置默认为单例
@Component
@Scope("prototype")
public class Person {
}
b. @Lazy: 配置修饰的类的bean采用懒加载机制
@Component
@Lazy
public class Person02 {
public Person02(){
System.out.println("init...");
}
}
c. @PostConstruct: 在bean对应的类中,修饰某个方法,将该方法声明为初始化方法,对象创建之后立即执行
d. @PreDestroy:在bean对应的类中,修饰某个方法,将该方法声明为销毁的方法,对象销毁之前调用的方法
@Component
public class JDBCUtils {
/*
* 初始化方法
* */
@PostConstruct
public void initConn(){
System.out.println("连接数据库");
}
/*
* 销毁方法
* */
@PreDestroy
public void destroyConn(){
System.out.println("销毁数据库连接");
}
/*
* 普通方法
* */
public void insert(){
System.out.println("插入");
}
/*
* 普通方法
* */
public void delete(){
System.out.println("删除");
}
}
e. @Controller @Service @Repository @Component:
在层与层之间设计接口 (面向接口编程) 并通过Spring注册对象
Web层:
package cn.zss.web;
@Controller
public class UserServlet {
@Autowired
private UserService userService = null;
public void regist(){
System.out.println("userServlet ... regist ...");
userService.regist();
}
}
Service层:
a. 接口UserService
package cn.zss.service;
public interface UserService {
public void regist();
}
b. 接口的实现类UserServiceImpl
package cn.zss.service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
@Qualifier("userDao")
private UserDao userDao = null;
@Override
public void regist() {
System.out.println("userService ... regist");
userDao.insert();
}
}
DAO层:
a. 接口
package cn.zss.dao;
public interface UserDao {
void insert();
}
b. 接口的第一个实现类
package cn.zss.dao;
import org.springframework.stereotype.Repository;
@Repository("userDao")
public class MySqlUserDao implements UserDao{
@Override
public void insert() {
System.out.println("Mysql ... insert ...");
}
}
c. 接口的第二个实现类
package cn.zss.dao;
import org.springframework.stereotype.Repository;
@Repository
public class OracleUserDao implements UserDao {
@Override
public void insert() {
System.out.println("Oracle ... insert ...");
}
}