這是一個沉澱的過程,大概第一次接觸Spring是在去年的這個時候,當初在實訓,初次接觸Java web,直接學習SSM框架(當是Servlet都沒有學),因而,養成了一個很很差的學習習慣,就是「照貓畫虎」。別人作什麼,照着樣子就是了,沒有任何的思考,這樣的學習習慣確定不會走太遠。如今我產生不少疑惑,這是什麼?爲何這麼作?如何作的更好?所以此次筆記的主題就是《這是什麼?》html
public interface UserService { public void addUser(); } public class UserServiceImpl implements UserService{ @Override public void addUser() { System.out.println("add a User"); } }
<?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.xsd"> <!-- 配置service <bean> 配置須要建立的對象 id :用於以後從spring容器得到實例時使用的 class :須要建立實例的全限定類名 --> <bean id="userService" class="com.springlearning.ioc.UserServiceImpl"></bean> </beans>
@Test public void demo02(){ //從spring容器得到 //1 得到容器 String xmlPath = "com/springlearning/ioc/beans.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); //2得到內容 --不須要本身new,都是從spring容器得到 UserService userService = (UserService) applicationContext.getBean("userServiceId"); userService.addUser(); }
class B{ private A a; //B類依賴A類 }
依賴:一個對象須要使用另一個對象
注入:經過setter方法進行另外一個對象實例設置java
class BookServiceImpl{ //以前開發:接口 = 實現類 (service和dao耦合) //private BookDao bookDao = new BookDaoImpl(); //spring以後 (解耦:service實現類使用dao接口,不知道具體的實現類) private BookDao bookDao; setter方法 }
模擬spring執行過程
建立service實例:BookService bookService = new BookServiceImpl() -->IoC <bean>
建立dao實例:BookDao bookDao = new BookDaoImple() -->IoC
將dao設置給service:bookService.setBookDao(bookDao); -->DI <property>web
public interface BookDao { public void addBook(); } public class BookDaoImpl implements BookDao { @Override public void addBook() { System.out.println("add a book"); } }
public interface BookService { void addBook(); } public class BookServiceImpl implements BookService { //方式1: 以前 , 接口=實現類 //private BookDao bookDao = new BookDaoImpl(); //方式2: 接口+ setter private BookDao bookDao; public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } @Override public void addBook() { bookDao.addBook(); } }
<?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.xsd"> <!-- 模擬spring執行過程 建立service實例:BookService bookService = new BookServiceImpl() IoC <bean> 建立dao實例:BookDao bookDao = new BookDaoImpl() IoC 將dao設置給service:bookService.setBookDao(bookDao); DI <property> <property> 用於進行屬性注入 name: bean的屬性名,經過setter方法得到 setBookDao ##> BookDao ##> bookDao ref :另外一個bean的id值的引用 --> <!-- 建立service --> <bean id="bookService" class="com.springlearning.di.BookServiceImpl"> <property name="bookDao" ref="bookDao"></property> </bean> <!-- 建立dao實例 --> <bean id="bookDao" class="com.springlearning.di.BookDaoImpl"></bean> </beans>
@Test public void demo01(){ String xmlPath = "com/springlearning/di/beans.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); BookService bookService = (BookService) applicationContext.getBean("bookService"); bookService.addBook(); }
api總體瞭解,以後不使用,在學習過程須要。
spring
@Test public void demo02(){ String xmlPath = "com/springlearning/di/beans.xml"; BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(xmlPath)); BookService bookService = (BookService) beanFactory.getBean("bookService"); bookService.addBook(); }
3種bean實例化方式:默認構造、靜態工廠、實例工廠express
<bean id="" class=""> 必須提供默認構造
<bean id="" class="工廠全限定類名" factory-method="靜態方法">
public class MyBeanFactory { /** * 建立實例 * @return */ public static UserService createService(){ return new UserServiceImpl(); } }
<?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.xsd"> <!-- 將靜態工廠建立的實例交予spring class 肯定靜態工廠全限定類名 factory-method 肯定靜態方法名 --> <bean id="userService" class="com.springlearning.bean_xml.MyBeanFactory" factory-method="createService"></bean> </beans>
/** * @ClassName:MyBeanFactory * @author: donkey-boy * @desc 實例工廠,全部方法非靜態 * @date:2019/7/12 14:51 */ public class MyBeanFactory { /** * 建立實例 * @return */ public UserService createService(){ return new UserServiceImpl(); } }
<bean id="myBeanFactory" class="com.springlearning.bean_xml.MyBeanFactory"></bean> <!-- 得到userservice * factory-bean 肯定工廠實例 * factory-bean 肯定普通方法 --> <bean id="userService" factory-bean="myBeanFactory" factory-method="createService"></bean>
做用域:用於肯定spring建立bean實例個數
編程
<bean id="" class="" scope=""> <bean id="userService" class="*" scope="prototype" ></bean>
<bean id="" class="" init-method="初始化方法名稱" destroy-method="銷燬的方法名稱">
public class UserServiceImpl implements UserService { @Override public void addUser() { System.out.println("add a User"); } public void myInit(){ System.out.println("初始化"); } public void myDestroy(){ System.out.println("銷燬"); } }
<!-- init-method 用於配置初始化方法,準備數據等 destroy-method 用於配置銷燬方法,清理資源等 --> <bean id="userService" class="com.springlearning.lifecycle.UserServiceImpl" init-method="myInit" destroy-method="myDestroy"></bean>
@Test public void demo02() { String xmlPath = "com/springlearning/lifecycle/beans.xml"; ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); UserService userService = (UserService) applicationContext.getBean("userService"); userService.addUser(); //要求:1.容器必須close,銷燬方法執行; 2.必須是單例的 // applicationContext.getClass().getMethod("close").invoke(applicationContext); // * 此方法接口中沒有定義,實現類提供 applicationContext.close(); }
spring 提供一種機制,只要實現此接口BeanPostProcessor,並將實現類提供給spring容器,spring容器將自動執行,在初始化方法前執行before(),在初始化方法後執行after() 。 配置<bean class="">
api
spring提供工廠勾子,用於修改實例對象,能夠生成代理對象,是AOP底層。
模擬
A a =new A();
a = B.before(a) --> 將a的實例對象傳遞給後處理bean,能夠生成代理對象並返回。
a.init();
a = B.after(a);
a.addUser(); //生成代理對象,目的在目標方法先後執行(例如:開啓事務、提交事務)
a.destroy()數組
public class MyBeanPostProcessor implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean,String beanName) throws BeansException{ System.out.println("前方法: "+ beanName); return bean; } public Object postProcessAfterInitialization(final Object bean ,String beanName) throws BeansException{ System.out.println("後方法: "+ beanName); return Proxy.newProxyInstance( MyBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object o, Method method, Object[] objects) throws Throwable { System.out.println("-----開啓事物"); Object obj = method.invoke(bean,objects); System.out.println("-----提交事物"); return obj; } } ); } }
<!-- 將後處理的實現類註冊給spring --> <bean class="com.springlearning.lifecycle.MyBeanPostProcessor"></bean>
public class User { private Integer id; private String username; private Integer age; public User(Integer id, String username) { super(); this.id = id; this.username = username; } public User(String username,Integer age) { super(); this.username = username; this.age = age; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", age=" + age + '}'; } }
<!-- 構造方法注入 * <constructor-arg> 用於配置構造方法一個參數argument name :參數的名稱 value:設置普通數據 ref:引用數據,通常是另外一個bean id值 index :參數的索引號,從0開始 。若是隻有索引,匹配到了多個構造方法時,默認使用第一個。 type :肯定參數類型 例如:使用名稱name <constructor-arg name="username" value="jack"></constructor-arg> <constructor-arg name="age" value="18"></constructor-arg> 例如2:【類型type 和 索引 index】 <constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg> <constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg> --> <bean id="user" class="com.springlearning.constructor.User" > <constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg> <constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg> </bean>
<!-- setter方法注入 * 普通數據 <property name="" value="值"> 等效 <property name=""> <value>值 * 引用數據 <property name="" ref="另外一個bean"> 等效 <property name=""> <ref bean="另外一個bean"/> --> <bean id="user" class="com.springlearning.setter.User" > <property name="id" value="1"></property> <property name="username"> <value>gzy</value> </property> <property name="age" value="22" ></property> <property name="address" ref="address"></property> </bean> <bean id="address" class="com.springlearning.setter.Address"> <property name="addr" value="huhhot"></property> <property name="tel" value="1234"></property> </bean>
<bean id="user" class="com.springlearning.setter.User" p:username="gzy" p:age="22" p:address-ref="address" > </bean> <bean id="address" class="com.springlearning.setter.Address" p:addr="baotou" p:tel="123"> </bean>
<bean id="user" class="com.springlearning.setter.User" p:username="gzy" p:age="22" p:address-ref="address" > <property name="id" value="#{123}"></property> </bean> <bean id="address" class="com.springlearning.setter.Address" p:addr="baotou" p:tel="123"> </bean>
<!-- 集合的注入都是給<property>添加子標籤 數組:<array> List:<list> Set:<set> Map:<map> ,map存放k/v 鍵值對,使用<entry>描述 Properties:<props> <prop key=""></prop> 【】 普通數據:<value> 引用數據:<ref> --> <bean id="collData" class="com.springlearning.coll.CollData"> <property name="array"> <array> <value>alice</value> <value>bob</value> <value>carl</value> <value>Dick</value> </array> </property> <property name="list"> <list> <value>Emma</value> <value>Ford</value> <value>Harris</value> </list> </property> <property name="set"> <set> <value>張三</value> <value>李四</value> <value>王五</value> </set> </property> <property name="map"> <map> <entry key="alice" value="愛麗絲"></entry> <entry> <key><value>bob</value></key> <value>鮑勃</value> </entry> </map> </property> <property name="properties"> <props> <prop key="1">張三</prop> <prop key="2">李四</prop> <prop key="3">王五</prop> </props> </property> </bean>
<!--組件掃描,掃描含有註解的類--> <context:component-scan base-package="com.springlearning.annotation"></context:component-scan>
筆記源自傳智播客Spring教學服務器