详解Spring的bean以及注解开发
各种复杂类型的依赖注入
我们采用一个类的大杂烩的形式,新建一个Student
package com.lwh.pojo;
import java.util.*;
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private String wife;
private Properties info;
//省略tostring,和get,set方法
}
新建一个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-4.1.xsd">
<!--
bean这个标签就代表实例化了一个对象,id代表实例化的名字,class代表实例化类的路径
property标签代表设置参数,要求实例化的对象里必须有set方法,否则报错,
其中有俩个属性
ref代表传入的对象(写已经注册的bean的id)
value代表传入的值,例如说对象中有一个属性是String类型的,就直接传入值即可
-->
<bean id="address" class="com.lwh.pojo.Address"/>
<bean id="student" class="com.lwh.pojo.Student">
<!--第一种,普通值注入-->
<property name="name" value="芜湖"/>
<!--第二种,引用类型注入-->
<property name="address" ref="address"/>
<!--第三种,数组类型注入,array就是数组的意思-->
<property name="books">
<array>
<value>水浒</value>
<value>三国</value>
<value>红楼</value>
</array>
</property>
<!--第四种,list类型注入,相当于很多个普通值,就用value标签-->
<property name="hobbys">
<list>
<value>看书</value>
<value>打豆豆</value>
</list>
</property>
<!--第五种,List注入,map中装的是键值对,第一个是键key,值是第二个-->
<property name="card">
<map>
<entry key="学号" value="20190105865"/>
<entry key="学籍号" value="213254654651"/>
</map>
</property>
<!--第六种,set注入-->
<property name="games">
<set>
<value>LOL</value>
<value>dota</value>
</set>
</property>
<!--第七种,空值注入-->
<property name="wife">
<null/>
</property>
<!--第八种,Properties值注入,类似于数据库连接的Properties-->
<property name="info">
<props>
<prop key="driver">com.mysql.jdbc</prop>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
</beans>
拓展之P空间和C空间注入
新建一个User类
package com.lwh.pojo;
public class User {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + 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;
}
}
增加beans.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
<!--p命名空间注入,需要在beans中引入p,就相当于property-->
<bean id="user" class="com.lwh.pojo.User" p:name="芜湖" p:age="19"/>
<!--c空间注入,相当于通过构造器注入:construct-args-->
<bean id="user2" class="com.lwh.pojo.User" c:name="芜湖" p:age="19"/>
</beans>
Bean的作用域
-
singleton(单例模式)
这是spring的默认机制,无论到哪个dao里创建user,拿到的都是用一个user,也就是一旦创建就只有一个
<bean id="user" class="com.lwh.pojo.User" p:name="芜湖" p:age="19" scope="singleton"/>
-
prototype(原型模式)
每一次去getBean的时候都创建一个新的对象
<bean id="user" class="com.lwh.pojo.User" p:name="芜湖" p:age="19" scope="prototype"/>
-
request
-
session
-
application
-
webscoket
Bean的装配
三种装配方式
- 在XML中显示配置
- 在java中显示配置
- 隐式的自动装配bean
测试环境,pojo中有PC,People,Phone,资源文件是beans.xml
PC:
package com.lwh.pojo;
public class PC {
public void test(){
System.out.println("我的个人电脑!");
}
}
People:
package com.lwh.pojo;
public class People {
private String own;
public String getOwn() {
return own;
}
public void setOwn(String own) {
this.own = own;
}
private Phone phone;
private PC pc;
public Phone getPhone() {
return phone;
}
public void setPhone(Phone phone) {
this.phone = phone;
}
public PC getPc() {
return pc;
}
public void setPc(PC pc) {
this.pc = pc;
}
}
Phone:
package com.lwh.pojo;
public class Phone {
public void test(){
System.out.println("我的手机!");
}
}
beans.xml
<?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-4.1.xsd">
<bean id="pc" class="com.lwh.pojo.PC"/>
<bean id="phone" class="com.lwh.pojo.Phone"/>
<bean id="people" class="com.lwh.pojo.People" autowire="byName">
<property name="own" value="芜湖"/>
</bean>
</beans>
test:
import com.lwh.pojo.People;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Mytest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
People people = context.getBean("people", People.class);
people.getPc().test();
people.getPhone().test();
}
}
隐式自动装配:
byName就是寻找上下文中,people的set方法后面紧跟着的对象名,例如setPc,那么就会去寻找上下文中是否有叫pc的对象(也就是beanid叫pc的对象),有就自动装配,没有就报空指针异常,如果我讲第一个bean的id改为“pc123454”,那么就会出错
byType就是寻找上下文中,people中与对象类型相同的bean,与id无关,例如,我将第一个bean的id删除,也可以成功,将id改为“pc213234”也能装配成功,但是上下文中不能同时存在要自动装配的对象类型相同的bean,例如如果使用byType自动装配,就不能出现两个pc对象(bean),否则报错
<?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-4.1.xsd">
<bean class="com.lwh.pojo.PC"/>
<bean id="phone" class="com.lwh.pojo.Phone"/>
<bean id="people" class="com.lwh.pojo.People" autowire="byType">
<property name="own" value="芜湖"/>
</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"
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.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<context:annotation-config/>
</beans>
-
@Autowired
直接在属性上使用,也可以在set方法上使用,如果使用注解自动装配,我们可以不编写Set方法,前提是你这个自动装配的属性在IOC容器中要存在,切符合名字byname(也就是和使用byname装配的前提一致)
package com.lwh.pojo;
import org.springframework.beans.factory.annotation.Autowired;
public class People {
private String own;
@Autowired
private Phone phone;
@Autowired
private PC pc;
public String getOwn() {
return own;
}
public void setOwn(String own) {
this.own = own;
}
public Phone getPhone() {
return phone;
}
public PC getPc() {
return pc;
}
}
@Autowired(value=false)//代表可以将属性设置为null
那么如果我想创建多个相同类型的bean,但是还想要people自动装配怎么办?
-
@Qualifier
这个注解可以指定id装配
@Autowired @Qualifier(value = "pc1234") private PC pc;
然后在beans中有
<bean id="pc1234" class="com.lwh.pojo.PC"/> <bean id="pc123" class="com.lwh.pojo.PC"/>
-
@Resource
- 都可以与Autowired一样用于属性字段上自动装配
- @Autowired通过byType的方法实现
- @Resource默认通过byname的方式实现,如果找不到就使用byType如果两个都找不到就报错
使用注解开发
bean的注解注入
@Component注解
- beans.xml中导入依赖支持、
<?xml version="1.0" encoding="UTF-8"?>
<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-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<!--代表去扫描com.lwh.pojo下的类-->
<context:component-scan base-package="com.lwh.pojo"/>
<context:annotation-config/>
</beans>
- 类中加入注解
package com.lwh.pojo;
import org.springframework.stereotype.Component;
//这个注解就相当于<bean id="user" class="com.lwh.pojo.User/>
@Component
public class User {
public String name="芜湖";
}
属性的注解注入
@Value(可以用在属性或者set方法上)
package com.lwh.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//这个注解就相当于<bean id="user" class="com.lwh.pojo.User/>
@Component
public class User {
@Value("芜湖")//设置属性值
public String name;
}
衍生注解
@Component有几个衍生注解,会按照mvc三层架构分层
- dao【@Repository】
- service【@Service】
- controller【@Controller】
其实本质都是一样的,都是代表某个类去注册到Spring中,装配Bean
自动装配置
-
@Autowired
-
@Qualifier
-
@Resource
作用域
package com.lwh.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
//这个注解就相当于<bean id="user" class="com.lwh.pojo.User/>
@Component
@Scope("prototype")//原型模式,从bean容器中取一次就new一个新的对象
public class User {
@Value("芜湖")//设置属性值
public String name;
}
JavaConfig注解开发
采用纯java代码的形式配置spring,不再使用xml形式,新建一个子项目,代码结构如下:
config.java:
加入**@Configuration注解,代表这是一个java代码的config注册类,再注册一个bean,采用@Bean**注解,
package com.lwh.config;
import com.lwh.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.lwh.pojo")//就相当于扫描实体类
public class Config {
//以下语句就相当于<bean id="getUser" class="com.lwh.pojo.User"/>
//bean的id就是方法名,大小写区分
@Bean
public User getUser(){
return new User();
}
}
User.java
采用**@Component**自动准备bean,然后再往set方法上注入name值为“芜湖”
package com.lwh.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class User{
private String name;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
@Value("芜湖")
public void setName(String name) {
this.name = name;
}
}
Test.java
import com.lwh.config.Config;
import com.lwh.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test {
public static void main(String[] args) {
//注意!这里使用AnnotationConfigApplicationContext
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
User user = context.getBean("getUser", User.class);
System.out.println(user.getName() );
}
}