spring实例化Bean的三种方式
- 使用类中的无参构造方法
<bean id="people" class="com.young.action.People">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
</bean>
- 使用静态工厂
- 创建工厂类
public class BeanFactory {
public static User getUser01() {
return new User(1,"钢铁",18);
}
public static User getUser02() {
return new User(2,"富贵",20);
}
}
2. class的值是工厂类的全路径,factory-method的值是需要调用的方法;工厂类中不同的方法创建了不同的实例,通过调用不同的方法获得不同的实例
<bean id="user1" class="com.young.factory.BeanFactory" factory-method="getUser01" ></bean>
测试
public class Test {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("ApplicationContext.xml");
User bean = (User) app.getBean("user1");
System.out.println(bean);
}
}
- 使用实例工厂
- 修改工厂类
工厂类中的定义的是非静态方法,通过调用这些方法来获取石磊
- 修改工厂类
public class BeanFactory {
public User getUser01() {
return new User(1,"钢铁",18);
}
public User getUser02() {
return new User(2,"富贵",20);
}
}
2. 更改xml
调用非静态方法就需要先创建实例,在调用方法
<bean id="beanFactory" class="com.young.factory.BeanFactory"></bean>
<bean id="user1" factory-bean="beanFactory" factory-method="getUser01" ></bean>
3. 测试
public class Test {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("ApplicationContext.xml");
User bean = (User) app.getBean("user1");
System.out.println(bean);
}
}
Bean属性注入
1. 使用get set方法
Bean属性的注入是通过People的set方法给People实例的属性赋值的,因此property标签的name属性值people类中set方法的名字一样
<bean id="people" class="com.young.action.People">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
</bean>
2. 有参构造方法
type的值是对应属性的类型,可以省略,省略后,会自动识别属性的类型
<bean id="people" class="com.young.action.People">
<constructor-arg name="id" value="1" type="com.lang.Integer"></constructor-arg>
<constructor-arg name="name" value="秋娴" type="com.lang.String"></constructor-arg>
</bean>
其他非常规属性的注入
数组
arr是一个String[]型的数组
<bean id="animal" class="com.young.action.Animal">
<property name="arr">
<array>
<value>d1</value>
<value>d2</value>
<value>d3</value>
</array>
</property>
</bean>
arrBean是一个User[]型的数组
<bean id="user" class="com.young.action.User">
<property name="id" value="2"></property>
<property name="name" value="富贵"></property>
<property name="age" value="20"></property>
</bean>
<bean id="animal" class="com.young.action.Animal">
<property name="arrBean">
<array>
<!-- 在内部定义一个实例 -->
<bean class="com.young.action.User">
<property name="id" value="1"></property>
<property name="name" value="钢铁"></property>
<property name="age" value="18"></property>
</bean>
<!-- 引入外部的实例 -->
<ref bean="user"/>
</array>
</property>
</bean>
map
params是一个Map<String,Object> 型的集合
<bean id="animal" class="com.young.action.Animal">
<property name="params">
<map>
<entry key="d1" value="秋娴"></entry>
<entry key="d2">
<bean class="com.young.action.People">
<property name="id" value="1"></property>
<property name="name" value="秋娴"></property>
</bean>
</entry>
</map>
</property>
</bean>
list
list是一个List型的集合,
<bean id="animal" class="com.young.action.Animal">
<property name="list">
<list>
<value>张三</value>
<value>李四</value>
<value>秋娴</value>
</list>
</property>
</bean>
listMap是一个List<Map<String,Object>>型的集合
<bean id="people" class="com.young.action.People">
<constructor-arg name="id" value="1" type="com.lang.Integer"></constructor-arg>
<constructor-arg name="name" value="钢铁" type="com.lang.String"></constructor-arg>
</bean>
<bean id="animal" class="com.young.action.Animal">
<property name="listMap">
<list>
<map>
<entry key="people01" value-ref="people"></entry>
</map>
<map>
<entry key="d1" value="钢铁"></entry>
<entry key="d2">
<bean class="com.young.action.People">
<property name="id" value="1"></property>
<property name="name" value="钢铁"></property>
</bean>
</entry>
</map>
</list>
</property>
</bean>
listBean是一个List型的集合
<property name="listBean">
<list>
<bean class="com.young.action.People">
<property name="id" value="1"></property>
<property name="name" value="秋娴"></property>
</bean>
<bean class="com.young.action.People">
<property name="id" value="2"></property>
<property name="name" value="张三"></property>
</bean>
<bean class="com.young.action.People">
<property name="id" value="2"></property>
<property name="name" value="李四"></property>
</bean>
</list>
</property>
Properties的注入
- Properties作为一个类的属性时
<bean id="xxx" class="xxxx">
<property name="properties">
<props>
<prop key="driver">com.mysql.jdbc</prop>
<prop key="url">jdbc:mysql://127.0.0.1:3306/</prop>
<prop key="userName">root</prop>
<prop key="password">ky123456</prop>
</props>
</property>
- 外部properties的引入
外部properties的引入需要引入约束条件,并且引入properties文件;从properties中读取到的值可以用一个JavaBean接收
<!--引入properties文件-->
<context:property-placeholder location="classpath:JdbcUtil.properties"/>
<bean id="dbProp" class="com.young.action.DbProp">
<property name="driver" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="userName" value="${username}"></property>
<property name="password" value="${password}"></property>
</bean>
注意:以上的方式得到的userName的值为配置环境里的名称。
为了能获取properties中的值,有两种方法
第一种方法,将${userName}中的名称改成其它名称,名称不能为username,name,其它的都可以
<context:property-placeholder location="classpath:JdbcUtil.properties"/>
<bean id="dbProp" class="com.young.action.DbProp">
<property name="driver" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="userName" value="${name01}"></property>
<property name="password" value="${password}"></property>
</bean>
第二种方法,在引入文件的标签中,加入 system-properties-mode,有两个参数值:
system-properties-mode
FALLBACK—>设置不去读取系统的环境变量 ,
ENVIRONMENT—>优先读取环境变量
将 system-properties-mode 设为FALLBACK;
<context:property-placeholder location="classpath:JdbcUtil.properties" system-properties-mode="FALLBACK"/>
<bean id="dbProp" class="com.young.action.DbProp">
<property name="driver" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="userName" value="${username}"></property>
<property name="password" value="${password}"></property>
</bean>
xml方式重构三层结构
写applicationContext.xml文件
ref的值是引用对象的id
public class UserDaoImpl implements UserDao {
@Override
public User query(int id) {
User user = null;
switch(id) {
case 1:
user = new User(1,"张三",18);
break;
case 2:
user = new User(2,"王富贵",19);
break;
case 3:
user = new User(3,"钢铁",20);
break;
}
return user;
}
}
UserServiceImpl.java
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public User query(int id) {
return new UserDaoImpl().query(id);
}
}
Action.java
public class Action {
UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void getUser() {
int id = 1;
User user = userService.query(id);
System.out.println(user);
}
}
测试
public class TestSpring {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
Action bean = (Action) app.getBean("action");
bean.getUser();
}
}
在回过头来看applicationContext.xml文件,如果把bean标签内的property标签删除,再进行测试,就会报空指针异常
<!--以下配置会报空指针异常-->
<!--创建UserDao实例-->
<bean id="userDao" class="com.young.dao.Impl.UserDaoImpl">
</bean>
<!--ref指向UserDao实例-->
<bean id="userService" class="com.young.service.impl.UserServiceImpl">
</bean>
<!--ref指向UserService实例-->
<bean id="action" class="com.young.action.Action">
</bean>
如何解决这类问题呢?
在Spring中,可以自动创建实例,通过给bean标签的属性autowire赋值,来设置如何创建实例,这就是自动装配,以下实现自动装配的配置
<bean id="userDao"
class="com.young.dao.Impl.UserDaoImpl">
</bean>
<bean id="userService"
class="com.young.service.impl.UserServiceImpl" autowire="byName">
</bean>
<bean id="action"
class="com.young.action.Action" autowire="byName">
</bean>
autowire有两个值
- byName–>根据对象里面的属性名取IOC容器里找对应id的对象
- byType–>根据对象里面属性的类型取Ioc容器里面找对象
在开发中,随着需求的增多,servlet类,Dao类,Service类会非常多,如果他们的配置都写在一个文件中的话,会特别的繁琐,为解决这个问题,于是就有了拆分配置文件这种骚操作
拆分配置文件
将applicationContext.xml 分成是三个文件
- application-dao.xml—>专门dao的bean标签
- application-service.xml—>专门放service的bean标签
- application-servlet.xml—>专门放action的bean标签
然后在applicationContext.xml中导入各个xml文件,这个文件什么也不写,只写导入的标签 - 配置application-dao.xml文件
<bean id="userDao"
class="com.young.dao.Impl.UserDaoImpl">
</bean>
- 配置application-service.xml文件
<bean id="userService"
class="com.young.service.impl.UserServiceImpl" autowire="byName">
</bean>
- 配置application-servlet.xml文件
<bean id="servlet"
class="com.young.servlet.UserServlet" autowire="byName">
</bean>
- 在applicationContext.xml中导入各个xml文件
<import resource="application-servlet.xml"/>
<import resource="application-dao.xml"/>
<import resource="application-service.xml"/>
那么有没有更牛皮的方式呢?何谓更牛皮的方式,就是配置文件都不用写了,就可以进行操作了;这就是注解方式重构三层结构
注解方式重构三层结构
就是同过注解的方式,实现不用写配置 文件也能创建实例,有以下几个注解
@Component 代表一个spring的组件 ,加载在类上
@Controller 被Component 注解了。主要作用于接收用户请求的类
@Service 被Component 注解了 主要作用于服务层
@Repository 被Component 注解了 主要作用于数据访问层
@Autowired 作用于类里面的属性或方法 用于自动从IOC容器里面根据类型去装配,加载在类的属性或方法上
只使用@Component和@Autowired两个注解就可以实现创建实例的功能了,@Controller ,@Service,@Repository都加载了@Component
useDaoImpl.java
@Component
public class UserDaoImpl implements UserDao {
@Override
public User query(int id) {
User user = null;
switch(id) {
case 1:
user = new User(1,"秋娴",18);
break;
case 2:
user = new User(2,"王富贵",19);
break;
case 3:
user = new User(3,"钢铁",20);
break;
}
return user;
}
}
UserServiceImpl.java
@Component
public class UserServiceImpl implements UserService {
@Autowired
private UserDao <u>userDao</u>;
@Override
public User query(int id) {
return new UserDaoImpl().query(id);
}
}
UserServlet.java
@Component
public class UserServlet {
@Autowired
UserService userService;
public void getUser() {
int id = 1;
User user = userService.query(id);
System.out.println(user);
}
}
在applicationContext.xml文件中写入扫描标签,标签的内容是需扫描的包,其作用是扫描各个类中的注解
<context:component-scan base-package="com.young.dao.Impl"></context:component-scan>
<context:component-scan base-package="com.young.service.impl"></context:component-scan>
<context:component-scan base-package="com.young.servlet"></context:component-scan>
测试
public class TestSpring {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserServlet bean = (UserServlet) app.getBean(UserServlet.class);
bean.getUser();
}
}