spring中使用注解代替xml配置

今天两部分内容,第一部分是注解,使用注解配置Spring,然后第二个是Spring中的AOP,今天就需要这两部分,

也没有练习,第一个注解配置Spring,这三大框架都是用注解来配置,这三大框架,都是支持用注解配置的,

那么三大框架的出现都是在JAVA1.5以前的,这样1.5推出之后,只要有一个框架用了注解,这两个框架不好意思

不用,实际上这三个框架都支持使用注解了,但是Hibernate,还有咱们的Struts,咋没说注解的事呢,那是因为,

在企业开发当中,很少在hibernate和struts中用注解来开发,因为struts和hibernate用注解开发的话,导致咱们的类

写的乱七八糟的,而至于这个注解,使用最多的框架,那就是Spring,所以Spring这里面,是要讲注解配置的,需要大家学习

一下的,那第一个看下注解配置Spring,这个知识点也没啥技术含量,看一下今天有哪些注解,代替昨天哪些配置文件就完事了,

讲起来还是比较简单的,注解代替配置文件的,昨天写的那些配置,都可以不用,然后用注解来代替,是这么点事,那咱们先做点

准备工作,创建一个项目,spring_day02,然后准备工作第一导包,直接把这6个包加进来

第一步导包就完事了,第二步咱们准备对象,对象,咱们看有没有现成的对象用,就用昨天现成的对象,

昨天的对象很典型
package com.learn.bean;

/**
 * @author Leon.Sun
 */
public class User {
	
	public User() {
		System.out.println("User空参构造方法");
	}
	
	private String name;
	
	private Integer age;
	
	private Car car;
	
	public User(String name, Car car) {
		System.out.println("User(String name, Car car)");
		this.name = name;
		this.car = car;
	}
	
	public User(Car car, String name) {
		System.out.println("User(Car car, String name)");
		this.name = name;
		this.car = car;
	}
	
	public User(Integer name, Car car) {
		System.out.println("User(Integer name, Car car)");
		this.name = name + "";
		this.car = car;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}
	
	public void init() {
		System.out.println("我是初始化方法!");
	}
	
	public void destory() {
		System.out.println("我是销毁方法!");
	}
	
	public Car getCar() {
		return car;
	}

	public void setCar(Car car) {
		this.car = car;
	}

	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
	}

}
package com.learn.bean;

public class Car {
	
	private String name;
	
	private String color;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	@Override
	public String toString() {
		return "Car [name=" + name + ", color=" + color + "]";
	}

}
再把咱们的配置文件拿过来,接下来的话,注解配置开始讲了,这里面没什么道理,就是看怎么做就行了,

第一步,需要为咱们的主配置文件,引入新的命名空间,或者叫做约束,昨天咱们导入的一个约束叫做beans,

还记得吗,那个xsd文件,你要是玩注解配置,包倒不要倒什么新包,但是你的这个配置文件呢,是需要再导入一个新的

约束的,那这里导入一个新的约束的话,我们自己都做过了,首先你得preferences cata

然后在这里add

spring,schema,咱们今天用的这个命名空间,第一个要用的命名空间,是咱们的context

导法和昨天一模一样,你把最后的名字复制,这里补个斜杠加上,然后在这里选择Schema Location

然后引入到eclipse就完事了

再到咱们的Application这里面,右键xml edit,切换到design视图

然后在beans上右键edit

Edit namespace,然后点击add

因为他就一条道,然后再点Browse

选下面这个

找到刚才导入的context命名空间,往下找,这儿呢,是这个

是这个吧,然后呢,剩下的事情,把前面这一段粘到这里来,http://www.springframework.org/schema/context,

然后这里面听好,昨天的beans,Prefix前缀是空,但是在xml里面学过约束的知道,一个XML文档当中,只允许有一个

空的前缀,昨天学那个beans为空,那以后导入的命名空间绝对不能够为空了,所以以后导入新命名空间,需要干这么

一件事,把你刚才中间这一行,这一段的最后一个单词,复制粘贴到这里来,这就是前缀,相比昨天导beans,区别就在于,

前缀昨天是空,然后从昨天以后,今天开始,再导新的,都要把后面这个复制过来

新的命名空间就导入进来了,然后保存退出,这个时候看一下,第二步使用注解代替配置文件,相当于打开一个使用

注解的开关,这个开关的话,因为咱们要用啊,这个时候你打<context:前缀,就有很多context约束下的元素,然后我们

用到的是component-scan,这个component单词知道是啥意思不,组件,scan就是扫描,翻译过来就是自动扫描,咱们指定的

组件,在Spring里面组件就是对象,理解为对象,咱们把对象放在Spring容器里管理,在Spring官方来说,把Component都放进来了,

把组件放进来,所以理解成对象的扫描,后面这个是啥意思,base-package,基础包,他的意思就是给他一个包名,从包下去扫描

所有的类,扫这个包下的所有的类,看上面有没有注解,咱们放到容器这两个对象,都是在这个bean包下边,所以你把bean包这个

包名放到这,这是指定扫描这个包下的所有类中的注解,这里需要注意的是,在扫描包的时候,他不仅仅只扫描你给的这个包,如果

这个包还有子包的话,也会扫描的,知道啥意思不,假设这个bean包下还有个haha包,这也会扫描,haha下边还有个heihei包,也就是

他在扫描的时候,他需要扫描子孙,所有包的,当然你这个learn这个包扫不扫,这个不扫,只扫你这个包的子包和子孙包,他之前的

父包和爷包都不扫,这里面注意,在扫描时,扫描包时,会扫描指定包下的所有子孙包,当然很多人为了省事,比如全项目当中,所有项目

都想用注解,他们就可能配置成这样了,知道啥意思吗,这样就覆盖了所有,我们还是讲bean,这样的话第一步就完事了,把这个截个图

放到这儿,这样的话加个配置就可以了,然后接下来第三步,第三步就是在类中使用注解,完成配置
<?xml version="1.0" encoding="UTF-8"?>
<beans 
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
		xmlns="http://www.springframework.org/schema/beans" 
		xmlns:context="http://www.springframework.org/schema/context" 
		xsi:schemaLocation="http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-4.2.xsd 
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context-4.2.xsd ">
		
	<!-- 指定扫描com.learn.bean这个包下的所有类的注解 
		 注意:扫描包时,会扫描指定包下的所有子孙包
	-->
	<context:component-scan base-package="com.learn.bean"></context:component-scan>


</beans>
比如我们想把User对象配置到咱们的Spring容器当中,怎么做,这个构造我都给他删掉,想把User对象

配置到Spring容器当中的话,加上一个注解,@Component,这个叫组件,人家规定这个组件意思可明确了,

那就是把User注册到Spring容器中,这就是组件了,你也可以通过括号指定一个参数,这个参数的话用来指定对象

放到Spring当中的这个名称是什么,比如叫user,这个写完以后,相当于在我们XML里面,怎么配置,<bean name="user">,

然后class就是我们的User,你加这么一个注解,就相当于在这里面配置这个,咱们可以试一下,就加这一个注解,是不是好使,

然后复制一个Demo过来,测试类过来
package com.learn.bean;

import org.springframework.stereotype.Component;

@Component("user")
// <bean name="user" class="com.learn.bean.User">
public class User {
	
	public User() {
		System.out.println("User空参构造方法");
	}
	
	private String name;
	
	private Integer age;
	
	private Car car;
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}
	
	public void init() {
		System.out.println("我是初始化方法!");
	}
	
	public void destory() {
		System.out.println("我是销毁方法!");
	}
	
	public Car getCar() {
		return car;
	}

	public void setCar(Car car) {
		this.car = car;
	}

	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
	}

}
a_annotation注解,在这创建容器,我把这个注释打开就可以了,接下来你看,能不能获得咱们注册进来的User,

不能,报错了,报啥错呢
package com.learn.a_annotation;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.learn.bean.User;

public class Demo {
	
	/**
	 * 创建方式1:空参构造
	 */
	@Test
	public void fun1() {
		
		/**
		 * 1.创建容器
		 */
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		/**
		 * 2.向容器要"user"对象
		 */
		User u = (User)ac.getBean("user");
		
		/**
		 * 打印user对象
		 */
//		System.out.println(u);
		
	}
}
咱们这个要玩注解的话,还得导一个包,他需要导入AOP包,老版本的不需要,spring-aop-4.2.4.RELEASE.jar,

我们把这个步骤添加上,这个是新版本的

这个模块在这里还要用到的,导完这个包之后,接下来再执行一下,是不是就获取到这个对象了,这个时候就使用到了

Component注解了,代替了咱们的bean语言,当然这里还有一个问题就是,Component这个注解,Spring在注册bean的时候,

一个早期注解,后来呢,又出现了这么几个注解,@Service注解,user,还有@Controller,还有@Repository注解,后来又衍生

出来这三个注解,啥意思呢,当年刚出现注解的时候,注册bean只有一个注解,就是Component,后来使用者给Spring反馈,

咱们注册项目当中所有对象的时候,都用的同一个注解,这样的话通过注解,很难区分对象是属于哪一层,Spring听了以后说,

想一想,那咱们这样解决吧,我再找出来三个注解,这三个注解和Component没有任何区别,但是呢,这三注解,通过他的名字,

你就能知道,你注册的对象是属于哪一层的对象,换句话讲,对我们使用者来说,要想注册一个Service层的对象,那你是不是

可以使用这个注解,用于注册Service层,那这个Controller,注册什么层的呢,WEB层,为啥是WEB层,这个我们讲MVC的时候,

WEB就是servlet,或者咱们的action之类的,Repository其实是仓库的意思,仓库指的就是数据仓库,数据库,所以它是用来

注册DAO层的,所以我们要学如何把对象注册到容器当中,一共有四种办法,但是推荐使用能够体现分成的三种,这个是具体注解,

将对象注册到容器中,就使用这三个注解,就这么简单,然后接下来
package com.learn.bean;

import org.springframework.stereotype.Repository;

//@Component("user")
// <bean name="user" class="com.learn.bean.User">
//	@Service("user")
//	@Controller("user")
	@Repository("user")
public class User {
	
	private String name;
	
	private Integer age;
	
	private Car car;
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}
	
	public Car getCar() {
		return car;
	}

	public void setCar(Car car) {
		this.car = car;
	}


}
这四个用哪个都一样,接下来第二个,咱们学会怎么注册bean之后,比如这个User对象,怎么决定他的作用范围,

是单例的,还是prototype多例的,这个是可以使用@Scope属性,你可以指定他的scopeName,如果是单例的话就是

singleton,如果是原型就是prototype,单例因为是默认值,你改单例就不用加了,你要用的话肯定是改原型,那

咱们来测一下
package com.learn.bean;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;

//@Component("user")
// <bean name="user" class="com.learn.bean.User">
//	@Service("user")
//	@Controller("user")
	@Repository("user")
	@Scope(scopeName="prototype")
public class User {
	
	private String name;
	
	private Integer age;
	
	private Car car;
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}
	
	public Car getCar() {
		return car;
	}

	public void setCar(Car car) {
		this.car = car;
	}


}
这个可以复制一份,u1,u2,是单例还是原型,打印一下u1==u2,那接下来咱们试一下,咱们改成原型,

势必导致是false
package com.learn.a_annotation;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.learn.bean.User;

public class Demo {
	
	/**
	 * 创建方式1:空参构造
	 */
	@Test
	public void fun1() {
		
		/**
		 * 1.创建容器
		 */
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		/**
		 * 2.向容器要"user"对象
		 */
		User u1 = (User)ac.getBean("user");
		User u2 = (User)ac.getBean("user");
		
		System.out.println(u1==u2);
		
		/**
		 * 打印user对象
		 */
//		System.out.println(u);
		
	}
}
比如我这个去掉,看他默认是不是单例的,执行一下,是不是true啊
package com.learn.bean;

import org.springframework.stereotype.Repository;

//@Component("user")
// <bean name="user" class="com.learn.bean.User">
//	@Service("user")
//	@Controller("user")
	@Repository("user")
//	@Scope(scopeName="prototype")
public class User {
	
	private String name;
	
	private Integer age;
	
	private Car car;
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}
	
	public Car getCar() {
		return car;
	}

	public void setCar(Car car) {
		this.car = car;
	}


}
package com.learn.a_annotation;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.learn.bean.User;

public class Demo {
	
	/**
	 * 创建方式1:空参构造
	 */
	@Test
	public void fun1() {
		
		/**
		 * 1.创建容器
		 */
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		/**
		 * 2.向容器要"user"对象
		 */
		User u1 = (User)ac.getBean("user");
		User u2 = (User)ac.getBean("user");
		
		System.out.println(u1==u2);
		
		/**
		 * 打印user对象
		 */
//		System.out.println(u);
		
	}
}
package com.learn.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

//@Component("user")
// <bean name="user" class="com.learn.bean.User">
//	@Service("user")
//	@Controller("user")
	@Repository("user")
//	@Scope(scopeName="prototype")
public class User {
	
	@Value("tom")
	private String name;
	
	private Integer age;
	
	private Car car;
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}
	
	public Car getCar() {
		return car;
	}

	public void setCar(Car car) {
		this.car = car;
	}

	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
	}


}
package com.learn.a_annotation;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.learn.bean.User;

public class Demo {
	
	/**
	 * 创建方式1:空参构造
	 */
	@Test
	public void fun1() {
		
		/**
		 * 1.创建容器
		 */
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		/**
		 * 2.向容器要"user"对象
		 */
		User u1 = (User)ac.getBean("user");
		
		/**
		 * 打印user对象
		 */
		System.out.println(u1);
		
	}
}
所以这里使用scope,指定对象的作用范围,这是咱们学习的第二个知识点,修改对象的作用范围,那下面咱们

还要学习关于属性的注入,比如说这个用户,来给他一个名字,怎么做呢,很简单,使用注解的话,是使用@Value的

注解,Value就是值,括号,这里你要填写一下,你要注入的值是什么,比如用户咱们给他一个名字,tom,这是不是给name

属性赋值,赋值是tom,相当于什么玩意,相当于这里加一个property,这我就不去写了,你们知道这是啥意思吧,就是把

tom这个值注入到name属性中,然后呢,直接执行一下,看控制台打印,
User [name=tom, age=null, car=null]

是不是有效果
但是跟你拓展一下,咱们这个使用value属性,注入值的时候,有两种选择实际上,一种是把value属性直接加载成员变量

内部上,还有一种是把注解加载setName方法上,加在这里也是可以的
package com.learn.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

//@Component("user")
// <bean name="user" class="com.learn.bean.User">
//	@Service("user")
//	@Controller("user")
	@Repository("user")
//	@Scope(scopeName="prototype")
public class User {
	
	private String name;
	
	private Integer age;
	
	private Car car;
	
	public String getName() {
		return name;
	}

	@Value("tom")
	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}
	
	public Car getCar() {
		return car;
	}

	public void setCar(Car car) {
		this.car = car;
	}

	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
	}


}
package com.learn.a_annotation;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.learn.bean.User;

public class Demo {
	
	/**
	 * 创建方式1:空参构造
	 */
	@Test
	public void fun1() {
		
		/**
		 * 1.创建容器
		 */
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		/**
		 * 2.向容器要"user"对象
		 */
		User u1 = (User)ac.getBean("user");
		
		/**
		 * 打印user对象
		 */
		System.out.println(u1);
		
	}
}
User [name=tom, age=null, car=null]
考虑一下,这两种有什么区别,一种是加在成员变量上的,还有一种是加在set方法上,这其实挺矛盾的,

说起来,为什么矛盾呢,你加在成员变量上,Spring在给这个对象赋值的时候,它是直接对field字段进行赋值,

对field字符按进行赋值,学过反射吗,知道Field是啥东西吗,它是操作字段进行赋值的,而如果你放在setName上,

他走的是set方法赋值的,通过反射的Field进行赋值,而下面是通过set方法赋值,这就是区别,当然对于我们赋值的结果

来说,好像都一样,但是从技术上来讲,上面这种方式来赋值的话,破坏了咱们对象的封装性,知道啥是破坏封装性吗,

这是学面向对象最基础的理论,面向对象三个特点,封装,继承和多态,啥叫封装,怎么举例子的,就是装电脑,然后你把

CPU,硬盘装好之后,是不是要放到机箱里,放到机箱里的过程就叫做封装,封装的目的是啥啊,就是没有必要直接去访问

到里面的CPU,那么你一摸就摸坏了,所以,把电脑的硬件都放在机箱里,什么音频插口,USB插口,是不是这个意思,那咱们封装类

是不是也如此,封装类的时候,把不希望外界看到的属性私有,然后只暴露共有的对外的操作的方法,get和set,是这个意思吗,

那要是加在成员变量上,那是不是就直接访问到内部的成员变量了,这是一个私有的,明白啥意思吗,所以他是破坏了封装性,

破坏了封装性就是面向对象,然后通过set方法赋值,它是推荐的,推荐使用,那毛病就毛病在这,在成员变量上加多清爽痛快,

在方法上加是多别扭,所以咱们日常使用的时候,反正效果是一样的,可能没有人在意这个东西了,大家都喜欢加载属性,

成员变量上,这个仁者见仁智者见智,感觉是一个取舍问题呢,然后呢这就是value属性,这块的话给age也赋上一个值,

括号给他来一个18岁,value等于18,注解学过吧,如果属性只有一个,并且名字是value,就可以忽略属性的键,记住这就是

一个结论,如果注解中只有一个需要赋值,并且属性名是value的话,那你是可以忽略属性键的,所以凡是不写键的,都是

给什么属性赋值,都是给value属性赋值
package com.learn.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

//@Component("user")
// <bean name="user" class="com.learn.bean.User">
//	@Service("user")
//	@Controller("user")
	@Repository("user")
//	@Scope(scopeName="prototype")
public class User {
	
	private String name;
	
	@Value(value="18")
	private Integer age;
	
	private Car car;
	
	public String getName() {
		return name;
	}

	@Value("tom")
	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}
	
	public Car getCar() {
		return car;
	}

	public void setCar(Car car) {
		this.car = car;
	}

	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
	}


}
User [name=tom, age=18, car=null]
然后age赋完值以后执行一下,是不是没问题
然后呢再往下,又该赋值了,只是赋值跟以前不太一样了,以前是值,现在是对象,那这个的话看好,

给对象赋值呢,这块的话有点讲究,你要是想把car属性赋值过来,首先你要把Car注册到容器当中,

所以在Car上加上@Component,然后括号,在这里给他取一个名字,car,这样的话car就放到容器当中了,

接下来我要把car注入给user
package com.learn.bean;

import org.springframework.stereotype.Component;

@Component("car")
public class Car {
	
	private String name;
	
	private String color;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	@Override
	public String toString() {
		return "Car [name=" + name + ", color=" + color + "]";
	}

}
看我这怎么写,有这么几种方式,第一种方式,也就是最简单的方式,只要加一个注解,@Autowired,

这就完事了,只要加一个Autowired,Car就会被封装进来,你看一下Car对象是不是有值了
package com.learn.bean;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

//@Component("user")
// <bean name="user" class="com.learn.bean.User">
//	@Service("user")
//	@Controller("user")
	@Repository("user")
//	@Scope(scopeName="prototype")
public class User {
	
	private String name;
	
	@Value(value="18")
	private Integer age;
	
	@Autowired
	private Car car;
	
	public String getName() {
		return name;
	}

	@Value("tom")
	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}
	
	public Car getCar() {
		return car;
	}

	public void setCar(Car car) {
		this.car = car;
	}

	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
	}


}
User [name=tom, age=18, car=Car [name=null, color=null]]
Car name昨天是兰博基尼,今天来个什么,玛莎拉蒂,然后color,来个呕吐绿,再执行下你看看,

是不是就进去了
package com.learn.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component("car")
public class Car {
	
	@Value("玛莎拉蒂")
	private String name;
	
	@Value("呕吐绿")
	private String color;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	@Override
	public String toString() {
		return "Car [name=" + name + ", color=" + color + "]";
	}

}
是不是就给了一个user,这就是第一种方式,叫Autowired,这个单词,Auto是不是自动,wire是不是穿

衣服的穿,翻译一般翻译成自动装配,那有的人说好神奇,怎么自动装配的,符合这个类型的对象,如果

检测到的话,找到这个对象,那你想,现在一看,这个Car类型,加了Autowired的,是不是会去容器中找Car

类型的对象,那是不是能找着,找着了一个Car,是不是就给他了,知道啥意思不,那这种写法,爽是爽,但是对象

一多的时候会有这个问题,你们猜到了,啥问题,这种自动装配的方式,假设我要把这个Car,注册了好几辆在容器

当中呢,听懂啥意思不,比如我有三辆车,在容器当中,那怎么能做到呢,你在这里放一个传统的bean,来一个name,

再来一个什么,class,这也是咱们的Car,然后这一块叫做car2,咱们这一块再来一个属性,比如property,name等于name,

value是布加迪威龙,那这样的话再看,现在我Spring容器当中,是不是两辆车
<?xml version="1.0" encoding="UTF-8"?>
<beans 
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
		xmlns="http://www.springframework.org/schema/beans" 
		xmlns:context="http://www.springframework.org/schema/context" 
		xsi:schemaLocation="http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-4.2.xsd 
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context-4.2.xsd ">
		
	<!-- 指定扫描com.learn.bean这个包下的所有类的注解 
		 注意:扫描包时,会扫描指定包下的所有子孙包
	-->
	<context:component-scan base-package="com.learn.bean"></context:component-scan>
	
	<bean name="car2" class="com.learn.bean.Car">
		<property name="name" value="布加迪威龙"></property>
		<property name="color" value="black"></property>
	</bean>


</beans>
package com.learn.a_annotation;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.learn.bean.User;

public class Demo {
	
	/**
	 * 创建方式1:空参构造
	 */
	@Test
	public void fun1() {
		
		/**
		 * 1.创建容器
		 */
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		/**
		 * 2.向容器要"user"对象
		 */
		User u1 = (User)ac.getBean("user");
		
		/**
		 * 打印user对象
		 */
		System.out.println(u1);
		
	}
}
那我这个自动装配的话,它是按照类型会去容器中匹配,那这样的话,你给他这么一装他就迷茫了,

哪辆呢,你看玛莎拉蒂

User [name=tom, age=18, car=Car [name=玛莎拉蒂, color=呕吐绿]]
第一种方式有个问题,就是如果有多个类型的话,他自动装配的话,自动装配的话又有一个问题,

如果匹配到多给类型一致的对象,将无法选择具体注入哪一个对象,这样的话怎么办呢,咱们给Autowired

加一个辅助注解,@Qualifer,然后这个注解,填入一个你要注入的名字,就像布加迪威龙,刚才咱们注册的叫

car2,那你就在这写上,car2,知道啥意思,这样的话等于说自动装配,告诉他找名为car2的车
package com.learn.bean;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

//@Component("user")
// <bean name="user" class="com.learn.bean.User">
//	@Service("user")
//	@Controller("user")
	@Repository("user")
//	@Scope(scopeName="prototype")
public class User {
	
	private String name;
	
	@Value(value="18")
	private Integer age;
	
	/**
	 * 自动装配
	 * 问题:如果匹配多个类型一致的对象,讲无法选择具体注入哪一个对象
	 */
	@Autowired
	@Qualifier("car2")
	private Car car;
	
	public String getName() {
		return name;
	}

	@Value("tom")
	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}
	
	public Car getCar() {
		return car;
	}

	public void setCar(Car car) {
		this.car = car;
	}

	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
	}


}
User [name=tom, age=18, car=Car [name=布加迪威龙, color=black]]
看到效果了吗,这样的话怎么找都是布加迪威龙,这样的话他就是第二种方式,使用Qualifier,使用

@Qualifier注解,告诉咱们的Spring容器,自动装配哪个名称的对象,这里成对配套使用,然后最后再介绍

一种方式,这两个先注掉,其实如果你是对象类型,有多个的话,其实并不建议你用这两个注解一块用,这样用

太罗嗦了,有一个注解他不是自动装配,直接指名道姓的,叫做Resource属性,指名道姓的告诉他要装配哪一个,

car2,这样的话一个注解,是不是就搞定了,他不是自动注解,他完全是手动注解,手动注入,指定注入哪个名称的

对象,这样的话是不是还是注入布加迪威龙,执行一下你看看,是不是这个效果
package com.learn.bean;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

//@Component("user")
// <bean name="user" class="com.learn.bean.User">
//	@Service("user")
//	@Controller("user")
	@Repository("user")
//	@Scope(scopeName="prototype")
public class User {
	
	private String name;
	
	@Value(value="18")
	private Integer age;
	
	/**
	 * 自动装配
	 * 问题:如果匹配多个类型一致的对象,讲无法选择具体注入哪一个对象
	 */
//	@Autowired
//	@Qualifier("car2")
	/**
	 * 手动注入,指定注入哪个名称的对象
	 */
	@Resource(name="car2")
	private Car car;
	
	public String getName() {
		return name;
	}

	@Value("tom")
	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}
	
	public Car getCar() {
		return car;
	}

	public void setCar(Car car) {
		this.car = car;
	}

	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
	}


}
User [name=tom, age=18, car=Car [name=布加迪威龙, color=black]]
你要想输出玛莎拉蒂,再执行一下
package com.learn.bean;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

//@Component("user")
// <bean name="user" class="com.learn.bean.User">
//	@Service("user")
//	@Controller("user")
	@Repository("user")
//	@Scope(scopeName="prototype")
public class User {
	
	private String name;
	
	@Value(value="18")
	private Integer age;
	
	/**
	 * 自动装配
	 * 问题:如果匹配多个类型一致的对象,讲无法选择具体注入哪一个对象
	 */
//	@Autowired
//	@Qualifier("car2")
	/**
	 * 手动注入,指定注入哪个名称的对象
	 */
	@Resource(name="car")
	private Car car;
	
	public String getName() {
		return name;
	}

	@Value("tom")
	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}
	
	public Car getCar() {
		return car;
	}

	public void setCar(Car car) {
		this.car = car;
	}

	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
	}


}
User [name=tom, age=18, car=Car [name=玛莎拉蒂, color=呕吐绿]]
是不是这个效果,这就是第三种注入对象的方式了,然后呢其中,推荐的话我其实推荐这种,

这就是三种对象类型的注入方式,然后咱们以后最好的方式,就是指名道姓,直接指定注入哪一个,

这是类型注入,接下来还没有完,最后有两个注解,比如说这个User,咱们指定一个初始化方法,销毁方法,

咱们配置文件不是学了,pubilc void init方法,这个就打印一下,这是初始化方法,比如这个init方法我想

让他作为初始化方法,可以在他这个方法上加上一个@PostConstruct,这个单词翻译过来,post是在什么之后,

Construct是不是构造,所以翻译过来是什么,构造之后调用,在对象被构造后,或者是被创建吧,创建后调用,

相当于咱们以前学过的什么东西,init-method,然后这个destory方法,叫做@PreDestroy,PreDestroy,Pre是在

什么之前,Destory是销毁,在对象销毁之前,调用的,相当于destroy-method,知道啥意思不
package com.learn.bean;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

//@Component("user")
// <bean name="user" class="com.learn.bean.User">
//	@Service("user")
//	@Controller("user")
	@Repository("user")
//	@Scope(scopeName="prototype")
public class User {
	
	private String name;
	
	@Value(value="18")
	private Integer age;
	
	/**
	 * 自动装配
	 * 问题:如果匹配多个类型一致的对象,讲无法选择具体注入哪一个对象
	 */
//	@Autowired
//	@Qualifier("car2")
	/**
	 * 手动注入,指定注入哪个名称的对象
	 */
	@Resource(name="car")
	private Car car;
	
	/**
	 * 在对象被创建后调用.init-method
	 */
	@PostConstruct
	public void init() {
		System.out.println("初始化方法!");
	}
	
	/**
	 * 在销毁之前调用 destroy-method
	 */
	@PreDestroy
	public void destory() {
		System.out.println("销毁方法!");
	}
	
	public String getName() {
		return name;
	}

	@Value("tom")
	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}
	
	public Car getCar() {
		return car;
	}

	public void setCar(Car car) {
		this.car = car;
	}

	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
	}


}
那接下来咱们再试一下看看,这里面咱们的销毁方法,你要想看到打印的话,你要调用它的close方法,

那这个close方法要调的话,引用得用子类,然后最后来一个ac.close,这回你再执行你看看,看到这个

效果了
package com.learn.a_annotation;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.learn.bean.User;

public class Demo {
	
	/**
	 * 创建方式1:空参构造
	 */
	@Test
	public void fun1() {
		
		/**
		 * 1.创建容器
		 */
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		/**
		 * 2.向容器要"user"对象
		 */
		User u1 = (User)ac.getBean("user");
		
		/**
		 * 打印user对象
		 */
		System.out.println(u1);
		
		ac.close();
		
	}
}
初始化方法!
User [name=tom, age=18, car=Car [name=玛莎拉蒂, color=呕吐绿]]
销毁方法!
作用域改成singleton,为啥呢,每次都创建一个新的,每次新的给你就不管了,只有放在容器中的

才会纳入完整性里面,看到了效果了,这样的话这就是咱们的初始化和销毁,初始化销毁,初始化以及销毁方法,

这样的话咱们注解就到这,这是Spring当中的注解,代替配置文件

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值