一、引用类型属性自动注入
-
对于引用类型属性的注入,也可不在配置文件中显示的注入。可以通过为<bean/>标签 设置 autowire 属性值,为引用类型属性进行隐式自动注入(默认是不自动注入引用类型属 性)。根据自动注入判断标准的不同,可以分为两种:
-
byName:根据名称自动注入
-
当配置文件中被调用者 bean 的 id 值与代码中调用者 bean 类的属性名相同时,可使用 byName 方式,让容器自动将被调用者 bean 注入给调用者 bean。容器是通过调用者的 bean 类的属性名与配置文件的被调用者 bean 的 id 进行比较而实现自动注入的。
-
-
byType: 根据类型自动注入
-
使用 byType 方式自动注入,要求:配置文件中被调用者 bean 的 class 属性指定的类, 要与代码中调用者 bean 类的某引用类型属性类型同源。即要么相同,要么有 is-a 关系(子 类,或是实现类)。但这样的同源的被调用 bean 只能有一个。多于一个,容器就不知该匹配 哪一个了。
-
-
public class School {
private String schoolName;
public String getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
@Override
public String toString() {
return "School{" +
"schoolName='" + schoolName + '\'' +
'}';
}
}
//====================================================
public class Student {
private String sname;
private int age;
private School mySchool;
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public School getMySchool() {
return mySchool;
}
public void setMySchool(School mySchool) {
this.mySchool = mySchool;
}
@Override
public String toString() {
return "Student{" +
"sname='" + sname + '\'' +
", age=" + age +
", mySchool=" + mySchool +
'}';
}
}
<bean id="school" class="com.pm.pack4.School">
<property name="schoolName" value="清华大学"/>
</bean>
<!--
要求Spring容器通过反射机制技术扫描当前类所有的属性。
如果发现了引用类型属性,且在Spring容器内部存在与当前
引用类型属性类型相匹配的对象则直接赋值(注入)
-->
<bean id="stu" class="com.pm.pack4.Student" autowire="byType">
<property name="sname" value="pm"/>
<property name="age" value="22"/>
</bean>
public class TestMain {
@Test
public void test4(){
ApplicationContext spring =
new ClassPathXmlApplicationContext("pack4/spring.xml");
Student student=(Student) spring.getBean("stu");
System.out.println(student.toString());
}
}
test4结果:Student{sname='pm', age=22, mySchool=School{schoolName='清华大学'}}
<bean id="yourSchool" class="com.pm.pack5.School">
<property name="schoolName" value="清华大学"/>
</bean>
<bean id="mySchool" class="com.pm.pack5.School">
<property name="schoolName" value="北京大学"/>
</bean>
<!--
要求Spring容器通过反射机制技术扫描当前类所有的属性。
如果发现了引用类型属性,且属性名称与Spring容器中
相关对象的id是相等,则要求Spring容器将这个id关联的对象
赋值给这个同名属性
-->
<bean id="stu" class="com.pm.pack5.Student" autowire="byName">
<property name="sname" value="mike"/>
<property name="age" value="22"/>
<!-- <property name="mySchool"/>-->
</bean>
public class TestMain {
@Test
public void test5(){
ApplicationContext spring =
new ClassPathXmlApplicationContext("pack5/spring.xml");
Student student=(Student) spring.getBean("stu");
System.out.println(student.toString());
}
}
test5结果:Student{sname='mike', age=22, mySchool=School{schoolName='北京大学'}}
二、如何通过注解的方式向Spring容器索要IOC服务
-
1、将@Compoent修饰在指定类名上,由@Compoent修饰的类,表示这个类对象需要由Spring容器提供,通过@Compoent(value = “key”) 指定当前类的实例对象在Spring容器中对应key。
此外也有不用通过@Compoent指定key。此时当前类的实例对象在Spring容器中对应的key是类名首字母小写。
2、在spring核心配置文件。通知Spring容器内部的【注解解析类】到指定的包下扫描所有绑定了@Compoent的类,并将这些类创建实例对象并保存到Spring容器中。
@Component
public class Student {
public void sayHello(String name){
System.out.println("hello "+name);
}
}
<!--
1.这个标签提供一个[扫描位置]
2.Spring容器到这个指定位置下扫描所有的类。
如果类上修饰了
@Component,@Controller,@Service,@Repository
则表示当前类的实例对象需要由Spring容器来提供
-->
<context:component-scan base-package="com.pm.entity"/>
public class TestMain {
/*
* ApplicationContext的两个接口实现类
*
* 1.FileSystemXmlApplicationContext:创建Spring容器对象可以在当前计算机任意硬盘上读取指定的spring
* 核心配置文件
*
* 2.ClassPathXmlApplicationContext:创建Spring容器对象只能在当前项目的编译路径下读取指定的核心配置文件
*
*/
@Test
public void test1(){
//1.获得Spring容器对象,Spring容器对象在创建时自动读取指定的Spring核心配置文件
ApplicationContext spring =new ClassPathXmlApplicationContext("spring.xml");
//2.向Spring容器对象索要Student类对象
Student stu =(Student)spring.getBean("student");
stu.sayHello("mike");
}
@Test
public void test2(){
//1.获得Spring容器对象,Spring容器对象在创建时自动读取指定的Spring核心配置文件
ApplicationContext spring =new ClassPathXmlApplicationContext("spring.xml");
//2.连续向Spring容器索要两个Student类型对象
Student s1 = (Student)spring.getBean("student");
Student s2 = (Student)spring.getBean("student");
System.out.println("s1 = "+s1.toString());
System.out.println("s2 = "+s2.toString());
}
@Test
public void test3(){
//1.获得Spring容器对象,Spring容器对象在创建时自动读取指定的Spring核心配置文件
ApplicationContext spring =new ClassPathXmlApplicationContext("spring.xml");
//2.获得Spring容器对象所管理的所有实例对象的key
String keys[]=spring.getBeanDefinitionNames();
for(String key:keys){
System.out.println("key = "+key);
}
}
}
三、如果通过注解的方式向Spring容器索要DI服务:
-
1、用于索要DI服务的两个注解
-
@Value:这个注解修饰在某个基本属性上。通知Spring容器对当前基本类型属性进行赋值,这个注解也可以修饰时在基本类型属性关联的set方法上。
此外如果这个注解修饰在基本属性上,此时这个基本属性可以不用声明set方法。
@Value注解出现的类必须修饰@Component,@Controller,@Service,@Repository中的一种注解。
-
@Component
public class Student {
@Value("10")
private int sid;
@Value("smith")
private String sname;
private int age;
@Override
public String toString() {
return "Student{" +
"sid=" + sid +
", sname='" + sname + '\'' +
", age=" + age +
'}';
}
}
<context:component-scan base-package="com.pm.pack1"/>
public class TestMain {
@Test
public void test1(){
ApplicationContext spring =
new ClassPathXmlApplicationContext("pack1/spring.xml");
Student stu =(Student) spring.getBean("student");
System.out.println(stu.toString());
}
}
test1结果:Student{sid=10, sname='smith', age=0}
2、@AutoWired:这个注解修饰在应用类型属性上,通知Spring容器对象使用容器内部与之匹 配的对象,为当前属性进行赋值。这个注解也可以修饰在引用类型属性关联的set方法上。 此外如果这个注解修饰在基本属性上,此时这个基本属性可以不用声明set方法。
@AutoWired注解出现的类必须修饰@Component,@Controller,@Service,@Repository 中的一种注解。
@Component
public class School {
@Value("北京大学")
private String schoolName;
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
@Override
public String toString() {
return "School{" +
"schoolName='" + schoolName + '\'' +
'}';
}
}
//=====================================================================
@Component
public class Student {
@Value("10")
private int sid;
@Value("smith")
private String sname;
//默认情况下要求Spring容器按照类型进行匹配
@Autowired
private School myScool;
@Override
public String toString() {
return "Student{" +
"sid=" + sid +
", sname='" + sname + '\'' +
", myScool=" + myScool +
'}';
}
}
<context:component-scan base-package="com.pm.pack2"/>
public class TestMain {
@Test
public void test2(){
ApplicationContext spring =
new ClassPathXmlApplicationContext("pack2/spring.xml");
Student stu =(Student)spring.getBean("student");
System.out.println(stu.toString());
}
}
test2结果:Student{sid=10, sname='smith', myScool=School{schoolName='北京大学'}}
四、JDK动态代理设计模式
-
JDK动态代理设计模式:简化对某个结构下所有的实现类进行同意修改,或者统一功能新增的开发难度。
-
1、面向切面:
-
切面对象来自于InvacationHandler接口实现类的实例对象;
-
切面对象负责实现【新增统一功能】;
-
负责接口上实现类中原有的方法与【新增功能】联合调用规则。
-
-
2、代理对象:
-
代理对象由JDK中工具类Proxy负责生产
-
代理对象用于监听指定接口下某个实现类的实例对象
-
在项目运行时,如果代理对象监听到程序需要被监听对象进行调用执行时,代理对象负责通知切面对象处理本次请求
-
代理对象相当于监听事件
-
-