今天两部分内容,第一部分是注解,使用注解配置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当中的注解,代替配置文件