- 作用域
<!--
bean的作用域:
singleton:單例(默認)
在整個IOC容器中只能存在一個bean對象
容器被創建的時候,就創建單例的bean對象,
後續每次通過getBean方法獲取Bean的時候,
都是同一個bean對象
單例的bean和單例的類不同
-->
<bean id="car" class="Scope.Car" scope="singleton">
<property name="brand" value="寶馬"/>
<property name="price" value="2111112123"/>
</bean>
<!--
prototype:多例
整個IOC容器中有多個可用的bean對象,在IOC被創建時不會
創建原型的bean對象,而是等到每次通過getBean的方法纔會
創建bean對象
-->
<bean id="cars" class="Scope.Car" scope="prototype">
<property name="brand" value="寶馬1"/>
<property name="price" value="21111121231"/>
</bean>
測試代碼如下:
@Test
public void testS(){
ApplicationContext applicationContext=new
ClassPathXmlApplicationContext("Spring_Scope.xml");
Car car1=applicationContext.getBean("car" ,Car.class);
Car car2=applicationContext.getBean("car" ,Car.class);
System.out.println(car1.equals(car2));
Car car3=applicationContext.getBean("cars",Car.class);
Car car4=applicationContext.getBean("cars",Car.class);
System.out.println(car3.equals(car4));
}
測試結果(測試階段,重寫了Car裏面的構造方法和set方法)
- SpringIOC的管理
① 通過構造器或工廠方法創建bean實例
② 爲bean的屬性設置值和對其他bean的引用
③ 調用bean的初始化方法
④ bean可以使用了
⑤ 當容器關閉時,調用bean的銷燬方法(在配置bean時,通過init-method和destroy-method 屬性爲bean指定初始化和銷燬方法)
後置處理器
① bean後置處理器允許在調用初始化方法前後對bean進行額外的處理
② bean後置處理器對IOC容器裏的所有bean實例逐一處理,而非單一實例。其典型 應用是:檢查bean屬性的正確性或根據特定的標準更改bean的屬性。
③ bean後置處理器時需要實現接口:
org.springframework.beans.factory.config.BeanPostProcessor。在初始化方法被調用前後,Spring將把每個bean實例分別傳遞給上述接口的以下兩個方法:
●postProcessBeforeInitialization(Object, String)
●postProcessAfterInitialization(Object, String)
添加bean後置處理器後bean的生命週期
①通過構造器或工廠方法創建bean實例
②爲bean的屬性設置值和對其他bean的引用
③將bean實例傳遞給bean後置處理器的postProcessBeforeInitialization()方法
④調用bean的初始化方法
⑤將bean實例傳遞給bean後置處理器的postProcessAfterInitialization()方法
⑥bean可以使用了
⑦當容器關閉時調用bean的銷燬方法
<bean id="car2" class="Scope.Car" init-method="init" destroy-method="destroy">
<property name="brand" value="寶馬1"/>
<property name="price" value="21111121231"/>
</bean>
<!--配置處理器,Spring能自動識別是一個後置處理器,所有的該XML文件裏面的Bean都會被該後置處理器進行管理-->
<bean class="Scope.MyBeanPost"></bean>
測試代碼:
@Test
public void test(){
ConfigurableApplicationContext applicationContext=new
ClassPathXmlApplicationContext("Spring_Scope.xml");
Car car=applicationContext.getBean("car2",Car.class);
System.out.println("第四個階段,使用bean對象"+car.toString());
applicationContext.close();
}
接口實現類:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* bean的後置處理器,對所有的bean都起作用
*/
public class MyBeanPost implements BeanPostProcessor {
/**
* 在初始化之前執行
* @param bean 正在被創建的bean對象
* @param beanName bean對象的id值
* @return
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("後置處理器加1");
return bean;
}
/**
* 在bean的生命週期的初始化方法之後執行
* @param bean 正在被創建的bean對象
* @param beanName bean對象的id值
* @return
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("後置處理器加2");
return bean;
}
}
配置數據庫連接池
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="root"/>
<property name="password" value="root"/>
<property name="jdbcUrl" value="jdbc:mysql:///test"/>
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
</bean>
引用外部的屬性文件(properties)
#K-V
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=qwsa1234
//之後要導入context的命名空間,這點上,eclipse的體驗的確要遠超於idea,
//在下面的source裏面把context打上對勾即可,而idea只能自己補全
<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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
//導入外部的屬性配置文件
<context:property-placeholder location="classpath*:db.properties"/>
<!--配置C3p0連接池-->
<bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
1)手動裝配:以value或ref的方式明確指定屬性值都是手動裝配。
2)自動裝配:根據指定的裝配規則,不需要明確指定,Spring自動將匹配的屬性值注入bean中。
<bean id="car" class="Auto.Car">
<property name="brand" value="寶馬"/>
<property name="price" value="288811"/>
</bean>
<bean id="address" class="Auto.Address">
<property name="city" value="鄭州"/>
<property name="province" value="河南"/>
</bean>
<!--對person進行自動裝配
byName: 使用bean的屬性名與在IOC容器中找到一個id匹配的bean,匹配成功則裝配成功
bytype: 使用bean的屬性的類型與IOC容器中<bean>的class進行匹配
若唯一匹配則裝配成功,否則拋出異常
代碼重合度極高,只需要修改下autowire的屬性值就好了,就不一一列舉
-->
<bean id="person" class="Auto.Person" autowire="byName">
<property name="name" value="Tom"/>
</bean>
//對象類
public class Person {
private String name ;
private Car car ;
private Address address ;
//set和get還有toString就省略了,大家明白就好,Car和address的屬性一目了之
}
//測試代碼
@Test
public void testAutoWire() {
ApplicationContext ctx =
new ClassPathXmlApplicationContext("spring-autowire.xml");
Person person = ctx.getBean("person",Person.class);
System.out.println(person);
}
(必須有aop的jar包)
常用註解(MVC就不用再說了吧)
- 普通組件:@Component 標識一個受Spring IOC容器管理的組件
- 持久化層組件:@Repository 標識一個受Spring IOC容器管理的持久化層組件
- 業務邏輯層組件:@Service 標識一個受Spring IOC容器管理的業務邏輯層組件
- 表述層控制器組件:@Controller 標識一個受Spring IOC容器管理的表述層控制器組件
組件命名規則
- 默認情況:使用組件的簡單類名首字母小寫後得到的字符串作爲bean的id
- 使用組件註解的value屬性指定bean的id
注意:事實上Spring並沒有能力識別一個組件到底是不是它所標記的類型,即使將@Respository註解用在一個表述層控制器組件上面也不會產生任何錯誤,所以@Respository、@Service、@Controller這幾個註解僅僅是爲了讓開發人員自己明確當前的組件扮演的角色。
掃描
-組件被上述註解標識後還需要通過Spring進行掃描才能夠偵測到。
<!--base-package屬性指定一個需要掃描的基類包,Spring容器將會掃描這個基類包及其子包中的所有類。
當需要掃描多個包時可以使用逗號分隔。
如果僅希望掃描特定的類而非基包下的所有類,可使用resource-pattern屬性過濾特定的類 -->
<context:component-scan base-package="MVCt"/>
<context:component-scan
base-package="MVC"
resource-pattern="Dao/*.class"/>
<!--包含與排除-->
<context:component-scan base-package="MVC" >
<!--指定掃描
type=annotation:表示只包含帶有expression的註解
當使用include-filter的時候,需要將context:component裏面的
use-default-filters="false"
掃描的就只是include-filter中的規則指定的 組件
-->
<context:include-filter type="assignable" expression="MVC.controller.UserController"/>
<!-- 排除掃描
子節點表示要排除在外的目標類-->
<context:exclude-filter type="assignable" expression="MVC.controller.UserController"/>
</context:component-scan>
引用尚硅谷的過濾表達式
組件裝配
在指定要掃描的包時,context:component-scan 元素會自動註冊一個bean的後置處理器:AutowiredAnnotationBeanPostProcessor的實例。該後置處理器可以 自動裝配標記 了@Autowired、@Resource或@Inject註解的屬性。
package MVC.controller;
import MVC.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
/**
* @Cotroller 註解的作用:
* 相當於在xml文件中:
* <bean id="userController" class="com.atguigu.spring.annotation.controller.UserController">
*
* 註解默認的id值 就是類名首字母小寫, 可以在註解中手動指定id值:@Controller(value="id值")
* 可以簡寫爲:@Controller("id值")
*
*
*/
@Controller
public class UserController {
@Autowired
private UserService userService;
public void regist() {
userService.handleAddUser();
}
}
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoJdbcImpl implements UserDao{
@Override
public void addUser() {
System.out.println("UserDao Jdbc .....");
}
}
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoMybatisImpl implements UserDao {
@Override
public void addUser() {
System.out.println("UserDao Mybatis .....");
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
/**
* @Autowired 完成bean屬性的自動裝配
*
* 工作機制: 首先會使用byType的方式進行自動裝配,如果能唯一匹配,則裝配成功,
* 如果匹配到多個兼容類型的bean, 還會嘗試使用byName的方式進行唯一確定.
* 如果能唯一確定,則裝配成功,如果不能唯一確定,則裝配失敗,拋出異常.
*
* 默認情況下, 使用@Autowired標註的屬性必須被裝配,如果裝配不了,也會拋出異常.
* 可以使用required=false來設置不是必須要被裝配.
*
* 如果匹配到多個兼容類型的bean,可以使用@Qualifier來進一步指定要裝配的bean的id值 。
*
* @Autowired @Qualifier 註解即可在成員變量上,也可以加在對應的set方法上..
*
*/
@Autowired(required=false)
@Qualifier("userDaoJdbcImpl") //指定裝配的Bean的id
private UserDao userDao ;
// @Autowired(required=false) // 自動裝配 byName byType ?????
// @Qualifier("userDaoJdbcImpl")
// public void setUserDao(UserDao userDao) {
// this.userDao = userDao;
// }
@Override
public void handleAddUser() {
//處理業務
userDao.addUser();
}
}
運行結果如下