所谓的框架其实就是程序的架子,在这个程序的架子中,搭建起程序的基本的骨架,针对程序的通用问题给出了便捷的解决方案,可以使开发人员 基于框架快速开发具体的应用程序。
常见的框架
SSH: Struts2 (Web层) / Spring (Service层) / Hibernate (DAO层)
SSM: SpringMVC (Web层) / Spring (Service层) / MyBatis (DAO层)
Spring框架概述
Spring是一个Service层的框架,可以整合许多其它框架进行工作。
Spring的主要技术是 IoC (DI) & AoP
IoC (DI) — 控制反转 (依赖注入)AoP — 面向切面编程 Spring IoC IoC (DI) — 控制反转 (依赖注入)
IoC称之为控制反转,简单来说就是将对象的创建的权利及对象的生命周期的管理过程交由Spring框架来处理
开发过程中不再需要关注对象的创建和生命周期的管理,而是在需要时由Spring框架提供,这个由spring框架管理对象创建和生命周期的机制称之为控制反转
通过IoC + 接口,可以在软件分层实践中,将耦合性提取到Spring容器中进行管理。这样就可以实现软件分层中“高内聚,低耦合”目标中的低耦合了
创建对象的过程中Spring可以依据配置对对象的属性进行设置,这个过称之为依赖注入,即DI。
入门案例演示:
创建项目:创建基本的java项目
导入相关的jar包 (6+1)
创建配置文件 — applicationContext.xml 放置到源码目录下
在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:
在程序中通过Spring容器获取对象并使用:
public class Test01 {
@Test
public void test01(){
Person01 person01 = new Person01();
person01.say();
person01.eat();
}
@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();
}
}
初始化Spring容器,加载指定的配置文件,基于配置文件初始化Spring容器当解析到配置文件中的 推论: 默认情况下,多次获取同一个id的bean,得到的将是同一个对象。 不可以配置多个id相同的bean 可以配置多个id不同但class相同的bean 通过context.getBean()方法获取bean时,可以通过如下两种方式获取: 传入id值 传入class类型 通过class方式获取bean时,如果同一个类配置过多个bean,则在获取时因为无法确定到底要获取哪个bean会抛出异常。 SpringIOC在通过class获取bean时,如果找不到该类型的bean还会去检查是否存在该类型的子孙类型的bean,如果有则返回,如果找不到或找到多个则抛出异常。这符合java面向对象思想中的多态的特性。 在 Spring中提供了别名标签可以为配置的 通过类的无参构造方法创建对象 当用最普通方式配置一个 在Spring容器初始化时,通过 这种方式下spring创建对象,要求类必须有无参的构造,否则无法通过反射创建对象,会抛出异常。 通过静态工厂创建对象 工厂设计模式 (Factory Pattern) 通过工厂隐藏创建对象的细节,使用者不需要关注创建对象的细节,只要找到工厂调用对应的生产方法,就可以直接得到可用的对象
很多的时候,我们面对的类是无法通过无参构造去创建的,例如该类没有无参构造、是一抽象类等等情况,此时无法要求spring通过无参构造创建对象,此时可以使用静态工厂方式创建对象。 定义Person类 定义Person类的静态工厂 编写配置文件 创建对象 实例工厂创建对象 实例工厂也可以解决类是无法通过无参构造创建的问题,解决的思路和静态工厂类似,只不过实例工厂提供的方法不是静态的。 spring需要先创建出实例工厂的对象,再调用实例工厂对象上指定的普通方法来创建对象。所以实例工厂也需要配置到Spring中管理。 定义Person类的实例工厂 编写配置文件 创建对象 Spring工厂创建对象 定义Person类的Spring工厂 编写配置文件 创建对象 Spring容器管理的bean在默认情况下是单例的 (常用),即一个bean只会创建一个对象,存在内置 map中,之后无论获取多少次该bean,都返回同一个对象。 Spring默认采用单例方式,减少了对象的创建,从而减少了内存的消耗。 在实际开发中是存在多例的需求的,Spring也提供了选项可以将bean设置为多例模式。 配置单例模式 / 多例模式: bean在单例模式下的生命周期: bean在单例模式下,spring容器启动时解析xml发现该bean标签后,直接创建该bean的对象存入内部map中保存之后无论获取多少次返回的都是同一个bean直到容器销毁,spring关闭,内部的bean跟着被销毁
bean在多例模式下的生命周期: bean在多例模式下,spring容器启动时解析xml发现该bean标签后,只是将该bean进行管理,并不会创建对象此后每次使用 getBean()获取该bean时,spring都会重新创建该对象返回,每次都是一个新的对象这个对象spring容器并不会持有,什么销毁取决于使用该对象的用户自己什么时候销毁该对象 (即使关闭容器,对象也可以继续使用)。
懒加载机制
Spring默认会在容器初始化的过程中,解析xml,并将单例的bean创建并保存到map中 这样的机制在bean比较少时问题不大,但一旦bean非常多时,spring需要在启动的过程中花费大量的时间来创建bean,花费大量的空间存储bean,但这些bean可能很久都用不上,在时间和空间上的浪费显得非常的不值得。 所以Spring提供了懒加载机制。所谓的懒加载机制就是可以规定指定的bean不在启动时立即创建,而是在后续第一次用到时才创建,从而减轻在启动过程中对时间和内存的消耗。 懒加载机制只对单例bean有作用,对于多例bean设置懒加载没有意义。 懒加载的配置方式: 如果同时设定全局和指定bean的懒加载机制,且配置不相同,则对于该bean局部配置覆盖全局配置。 在Spring中如果某个bean在初始化之后或销毁之前需要做一些额外操作可以为该bean配置初始化和销毁的方法,在这些方法中完成要功能。 配置方式 (示例): 定义类 编写配置文件 测试 Spring中关键方法的执行顺序: 在Spring创建bean对象时,先创建对象 (通过无参构造或工厂)接着调用init方法来执行初始化操作之后此bean就可以调用其它普通方法而在对象销毁之前,spring容器调用其destory方法来执行销毁操作。
Spring DI
创建对象的过程中Spring可以依据配置对对象的属性进行设置,这个过称之为依赖注入,即DI 通常的javabean属性都会私有化,而对外暴露Getter和Setter方法,此时spring可以通过Setter方法将属性的值注入对象。 普通属性注入: a. 定义类 b. 编写配置文件 自定义bean的注入: a. 自定义类 b. 在Hero类中定义属性并提供get和set方法 c. 编写配置文件 自动装配 为指定 对象属性设置的另一种方式是在对象创建的过程中通过构造方法传入并设置对象的属性;Spring也可以通过这样的构造方法实现属性的注入 a. 定义类 b. 编写配置文件 c. 编写测试类 注释:java中注释的格式://, , 注解: sun在jdk5.0开始提供的新特性给程序看的提示信息,程序看后可以根据有无注解及注解上属性的不同配置执行不同的逻辑。java中的注解的格式:@Annoname(key=value,…) 注解在开发中,可以作为轻量化配置来使用,比起使用xml作为配置文件,更加的轻便易用,在java开发中大量的使用。 java 内置注解 @Override — 声明重写父类方法的注解,要求编译器帮我们检查是否成功的覆盖,如果没有成功覆盖父类方法,编译器将会进行报错提示。 @Deprecated — 声明方法被过时,不再建议使用,要求编译器在编译的过程中对于这样的方法的调用提出警告,提示方法过时。 @SuppressWarnings — 压制警告,提示编译器,在编译的过程中对指定类型的警告不再提示 注解可以基于有注解 / 没注解或者注解属性的不同来控制程序按照不同方式运行 注解常用作轻量化配置,替代配置文件的部分功能 注解方便开发阶段的配置和更改,配置文件在发布后仍可以方便修改,因此实际开发中注解和配置文件需要结合使用 开发一个注解类 开发一个注解类的过程,非常类似于开发一个接口,只不过需要通过@interface关键字来声明
使用元注解修饰注解的声明 所谓的元注解是用来修饰注解声明的注解,可以控制被修饰的注解的特性。
@Target:用来声明被修饰的注解可以用在什么位置。 可以在@Target的属性中设置ElementType类型的数组来指定可以使用的位置。如果不用此元注解修饰,默认注解可以用在任意位置。 @Retention:用来声明被修饰的注解会被保留到什么阶段。 java —> 编译 —> .class —> 类加载器 —> 字节码 可以在该注解的属性中通过RetentionPolicy类型的值来指定注解被保留到何时。 RetentionPolicy.SOURCE:此注解将会被保留到源码阶段,.java中;在编译过程中被删除。这种类型的注解通常是给编译器看的。 RetentionPolicy.CLASS:此注解将会被保留在源码阶段和编译阶段,.java和.class中;在类加载的过程中被删除。这种类型的注解通常是给类加载器看的。 RetentionPolicy.RUNTIME:此注解将会被保留在源码阶段,编译阶段和运行阶段,.java .class和内存中的字节码中都会存在。这种类型的注解通常用来在运行阶段进行反射,控制程序运行过程。 只有RUNTIME级别的注解才可以通过反射技术进行反射。 @documented :用来声明被修饰注解是否要被文档提取工具提取到文档中;javadoc命令可以用于生成文档 默认不提取。 @Inherited:用来声明被修饰的注解是否具有继承性 默认没有继承性 注解类中还可以声明属性。为注解类声明属性的过程非常类似于为接口定义方法。但要求,注解中的所有的属性必须是public的,可以显式声明,也可以不声明,不声明默认就是public的。注解中的属性只能是八种基本数据类型,String类型,Class类型,枚举类型,其他注解类型,及以上类型的一维数组。一旦声明了属性,在注解使用的过程中就必须为属性赋值,为其赋值的方式就是使用注解时,在注解后通过(属性名=属性值)的方式 指定属性的值也可以在声明注解时 在注解的属性后 通过default关键字,声明属性的默认值,声明过默认值的属性默认采用默认值,也可以手动赋值,覆盖默认值如果属性是 一维数组类型而在传入的数组中只有一个值,则包括数组的大括号可以省略如果注解的属性只有一个需要赋值,且该属性的名称叫做value,则在使用注解时,value=“xxx” 中的 ‘value=’ 可以不写
只有RUNNTIME级别的注解能够被反射Class Method Field Package… 都提供了获取注解信息的方法
基本实现流程: a. 导入开发包 b. 编写配置文件,并导入context约束 Idea可以将该配置文件设置为模板,方便以后使用 文件 —> 设置 —> 编辑器 —> 文件和代码模板 —> 点击左侧加号新建模板 c. 开启包扫描 在配置文件中,开启包扫描,指定Spring自动扫描哪些个包下的类;只有在指定的扫描包下的类上的IOC注解才会生效。 d. 使用注解注册bean 在配置的包中的类上使用@Component注解,则这个类会自动被注册为bean 使用当前类的class为的class,通常情况下使用类名首字母小写为的id 如果类名的第二个字母为大写则首字母保留原样,如类名: PErson —> id名: PErson 也可以通过在@Component中配置value属性,明确的指定bean的id e. 测试类 Spring默认通过反射创建bean,如果某些bean没有无参构造器或创建过程非常复杂,则无法通过简单的反射创建bean此时可以通过创建bean的工厂,令SpringIoC通过工厂来创建bean,从而进行注册。可以通过配置文件方式配置bean工厂,同样也可以通过注解配置bean工厂。
配置工厂类 工厂类必须放在包扫描目录下,且被@Component注解修饰
配置工厂类中生产bean的方法 工厂中生产bean的方法要被@Bean修饰 则此方法会被SpringIOC调用,并将返回的对象注册为Spring的bean 默认自动推断id (根据方法名,不常用),在老版本中通过@Bean(name=“xxx”)指定id;在新版本中,通过value属性指定id。 案例演示: a. 定义Dog类 b. 定义Dog类的工厂类 c. 测试 通过底层的反射机制实现 (可以突破私有的防控权限),既不依靠构造函数,也不依靠Set方法
a. 导入开发包 b. 编写配置文件 c. 注解方式注入spring内置支持的类型数据 - 非集合类型 spring中可以通过@Value注解来实现spring内置支持的类型的属性的注入。
这种方式可以实现Spring内置支持类型的注入,但是将注入的值写死在了代码中,后续如果希望改变注入的值,必须来修改源代码可以将这些值配置到一个properties配置文件中,再在Spring中进行引入。
d. 编写properties配置文件(my.properties)并加载 e. 添加@Value注解 f. 注解方式注入spring内置支持的类型数据 引入util名称空间,通过适当的util标签注册数据 再在类的属性中通过@Value注入赋值 g. 使用注解注入自定义bean类型数据 在bean中的属性上通过@Autowired实现自定义bean类型的属性注入 当Spring容器解析到@Component注解时,创建当前类的bean在Spring容器中进行管理,在创建bean的过程中发现了@Autowired注解,会根据当前bean类型,寻找在Spring中是否存在该类型的bean,找到直接注入,如果找不到还会检查是否有子孙类、实现类存在,如果存在唯一的则自动注入,如果还是没有找到或找到多个无法注入,则还会按照属性名对应id去查找对应的bean,如果存在则注入,如果还是没有找到则抛出异常。 也可以额外配置@Qualifier(value=“xxx”)注解强制要求按照id寻找bean,则此时会直接使用给定的id寻找bean,而不会进行基于类型的匹配。 a. @Scope(value=“prototype”):配置修饰的类的bean是单例还是多例,如果不配置默认为单例 b. @Lazy: 配置修饰的类的bean采用懒加载机制 c. @PostConstruct: 在bean对应的类中,修饰某个方法,将该方法声明为初始化方法,对象创建之后立即执行 d. @PreDestroy:在bean对应的类中,修饰某个方法,将该方法声明为销毁的方法,对象销毁之前调用的方法 e. @Controller @Service @Repository @Component: 这四个注解的功能是完全相同的,都是用来修饰类,将类声明为Spring管理的bean的。其中@Component一般认为是通用的注解而@Controller用在软件分层中的控制层,一般用在Web层而@Service用在软件分层中的业务访问层,一般用在Service层而@Repository用在软件分层中的数据访问层,一般用在DAO层
利用Spring IOC&DI 实现软件分层解耦
在层与层之间设计接口 (面向接口编程) 并通过Spring注册对象 Web层: Service层: a. 接口UserService b. 接口的实现类UserServiceImpl DAO层: a. 接口 b. 接口的第一个实现类 c. 接口的第二个实现类
@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
}
@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
}
IoC获取对象的方式
@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();
}
@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();
}
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创建对象的方式
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();
}
@Test
public void test02() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class clz = Class.forName("cn.zss.domain.Person01");
// 前提:类必须有无参构造函数
Person01 p = (Person01) clz.newInstance();
p.eat();
}
@Test
public void test03() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person01 p = (Person01)context.getBean("person01");
p.eat();
((ClassPathXmlApplicationContext)context).close();
}
}
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;
}
}
public class Person01StaticFactory {
// 私有化构造方法,保证静态工厂类无法实例化
private Person01StaticFactory(){}
// 提供公有静态方法用来生产目标对象
public static Person01 getInstance(){
return new Person01("lili",20,'女');
}
}
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();
}
}
public class Person01InstanceFactory {
public Person01 getInstance(){
return new Person01("Tom",20,'男');
}
}
@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();
}
单例和多例
public class Person01SpringFactory implements FactoryBean
@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();
}
public class JDBCUtils {
public void init(){
System.out.println("连接数据库");
}
public void destroy(){
System.out.println("销毁数据库连接");
}
public void getConn(){
System.out.println("获取连接");
}
}
public class Test01 {
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
JDBCUtils jdbcUtils = (JDBCUtils) context.getBean("jdbcUtils");
jdbcUtils.getConn();
((ClassPathXmlApplicationContext)context).close();
}
}
public class Hero {
private String name;
private int age;
private List
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 +
'}';
}
}
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;
}
}
?xml version="1.0" encoding="UTF-8"?>
基于构造方法的注入
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 +
'}';
}
}
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();
}
}
基于注解方式配置Spring IoC
注解
为注解增加属性
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface FirstAnno { // 自定义注解可以应用于属性和方法上
}
@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...");
}
}
反射注解
Spring注解方式实现IoC & DI
返回值 方法 Annotation[] getAnnotations ():返回此元素上存在的所有注释。 A getAnnotation (Class annotationClass): 如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。 boolean isAnnotationPresent (Class extends Annotation> annotationClass) : 如果指定类型的注释存在于此元素上,则返回 true,否则返回 false
package cn.zss.domain;
import org.springframework.stereotype.Component;
@Component //
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
package cn.zss.domain;
public class Dog {
public Dog (String name){
}
}
package cn.zss.domain;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class DogFactory {
//
@Test
public void test02(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Dog dog = (Dog)context.getBean("dog");
System.out.println(dog);
((ClassPathXmlApplicationContext)context).close();
}
Spring注解方式实现DI
package cn.zss.domain;
@Component
public class Hero {
@Value("美国队长")
private String name;
@Value("40")
private int age;
private List
myname = 美国队长
myage = 40
@Component
public class Hero {
@Value("${myname}")
private String name;
@Value("${myage}")
private int age;
private List
@Component
public class Hero {
@Value("${myname}")
private String name;
@Value("${myage}")
private int age;
@Value("#{@l1}")
private List
package cn.zss.domain;
@Component
public class Hero {
@Value("美国队长")
private String name;
@Value("100")
private int age;
@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 +
'}';
}
}
其他注解
@Component
@Scope("prototype")
public class Person {
}
@Component
@Lazy
public class Person02 {
public Person02(){
System.out.println("init...");
}
}
@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("删除");
}
}
package cn.zss.web;
@Controller
public class UserServlet {
@Autowired
private UserService userService = null;
public void regist(){
System.out.println("userServlet ... regist ...");
userService.regist();
}
}
package cn.zss.service;
public interface UserService {
public void regist();
}
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();
}
}
package cn.zss.dao;
public interface UserDao {
void insert();
}
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 ...");
}
}
package cn.zss.dao;
import org.springframework.stereotype.Repository;
@Repository
public class OracleUserDao implements UserDao {
@Override
public void insert() {
System.out.println("Oracle ... insert ...");
}
}



