IOC
public class IServiceImpl implements IService {
public void IserviceImpl(){}
@Override public void getService() { System.out.println("服務"); } }
applicationContext.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.xsd"> <bean id="myService" class="com.pack.Service.IServiceImpl"/> </beans>
ApplicationContext來加載類
通過ClassPathXmlApplicationContext來加載類
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); IService service = (IService) ac.getBean("myService"); service.getService();
通過FileSystemXmlApplicationContext加載
ApplicationContext ac = new FileSystemXmlApplicationContext();
IService service = (IService) ac.getBean("H:\\Program\\WorkSpace\\Java\\SpringLearn\\src\\applicationContext.xml");
service.getService();
BeanFactory
已廢用
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); IService service = (IService) bf.getBean("myService"); service.getService();
兩個容器的區(qū)別
ApplicationContext 在容器初始化時,會將所有的bean創(chuàng)建
優(yōu)點:響應快
缺點:占用資源
BeanFactory,在真正使用bean時才創(chuàng)建
優(yōu)點:不多占用系統(tǒng)資源
缺點:響應慢
相較于資源占用,我們一般選擇響應速度快的ApplicationContext
動態(tài)工廠
ServiceFactory
public class ServiceFactory {
public IService getService(){
return new IServiceImpl();
}
}
<bean id="myService" factory-bean="factory" factory-method="getService"/>
<bean id="factory" class="com.pack.Service.ServiceFactory"/>
String configLocation = "applicationContext.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(configLocation); IService service = (IService) ac.getBean("myService"); service.getService();
靜態(tài)工廠
<bean id="myService" class="com.pack.Service.ServiceFactory" factory-method="getService"/>
ServiceFactory
public class ServiceFactory { public static IService getService(){ return new IServiceImpl(); } }
Bean創(chuàng)建
<bean id="myService" class="com.pack.Service.ServiceFactory" factory-method="getService" scope="prototype"/>
scope 為bean的管理有singleton prototype request session
其對象的創(chuàng)建時機不是在初始化時,而是在訪問時
singleton是默認方式,創(chuàng)建在初始化時。
request 對于一個Http請求,創(chuàng)建一次
session 對于每一個Http-Session, 創(chuàng)建一次
Bean的生命周期
public class IServiceImpl implements IService, BeanNameAware, BeanFactoryAware, InitializingBean, DisposableBean { private String adao; public IServiceImpl(String adao) { System.out.println("step1: setter()"); } public void setAdao(String adao) { this.adao = adao; System.out.println("step2: setter()"); } @Override public String getService() { System.out.println("Step9: 服務");return "abcde"; } public IServiceImpl() { } @Override public void setUp() { System.out.println("Step7: bean初始化之后"); } @Override public void tearDown() { System.out.println("Step11: 終止"); } @Override public void setBeanName(String name) { System.out.println("Step3: BeanNameAware 獲取beanName" +name); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("BeanFactoryAware Step4: 獲取beanFactory"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("InitializingBean Step 6: bean初始化完畢"); } @Override public void destroy() throws Exception { System.out.println("InitializingBean Step 10: 實現接口的銷毀之前"); } }
public class BeanLife implements BeanPostProcessor { public BeanLife() { System.out.println("構造Bean"); } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("step5: 執(zhí)行Bean前處理"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("Step8: 執(zhí)行Bean后處理"); return bean; } }
Step1: 構造器 step2: setter() Step3: BeanNameAware 獲取beanNamemyService BeanFactoryAware Step4: 獲取beanFactory step5: 執(zhí)行Bean前處理 InitializingBean Step 6: bean初始化完畢 Step7: bean初始化之后 Step8: 執(zhí)行Bean后處理 Step9: 服務 InitializingBean Step 10: 實現接口的銷毀之前 Step11: 終止
Bean后處理器的應用
public class BeanLife implements BeanPostProcessor { public BeanLife() { System.out.println("構造Bean"); } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("執(zhí)行Bean前處理"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("執(zhí)行Bean后處理"); Object obj = Proxy.newProxyInstance( bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object object = method.invoke(bean, args); return ((String)object).toUpperCase(); } } ); return obj; } }
基于XML的設值注入
public class User { private String name; private Integer role; private Country country; @Override public String toString() { return "User{" + "name='" + name + '\'' + ", role=" + role + ", country=" + country + '}'; } public void setName(String name) {this.name = name;} public void setRole(Integer role) {this.role = role;} public void setCountry(Country country) {this.country = country;} }
要實現setter方法, Country實現 省略
<bean id="china" class="com.pack.beans.Country"> <property name="name" value="中國"/> </bean> <bean id="user" class="com.pack.beans.User"> <property name="name" value="李四"/> <property name="role" value="1"/> <property name="country" ref="china"/> </bean>
構造注入
public class User { private String name; private Integer role; private Country country; public User() { } public User(String name, Integer role, Country country) { this.name = name; this.role = role; this.country = country; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", role=" + role + ", country=" + country + '}'; } }
必須實現帶參構造器
<bean id="user" class="com.pack.beans.User">
<constructor-arg name="name" value="李四"/>
<constructor-arg index="1" value="1"/>
<constructor-arg ref="china"/>
</bean>
可以不寫index 但是順序必須和帶參構造器的順序一樣
p命名空間
<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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="china" class="com.pack.beans.Country">
<property name="name" value="中國"/>
</bean>
<bean id="user" class="com.pack.beans.User" p:name="李四" p:role="2" p:country-ref="china"/>
</beans>
c命名空間
xmlns:c="http://www.springframework.org/schema/c"
<bean id="user" class="com.pack.beans.User" c:name="李四" c:role="2" c:country-ref="china"/>
為集合屬性注入
<bean id="china" class="com.pack.beans.Country"> <property name="name" value="中國"/> </bean> <bean id="user" class="com.pack.beans.User"> <property name="name" value="李四"/> <property name="role"> <array> <value>1</value> <value>2</value> </array> </property> <property name="myList"> <list> <value>list1</value> <value>list2</value> </list> </property> <property name="mySet"> <set> <value>set1</value> <value>set2</value> </set> </property> <property name="country" ref="china"/> </bean>
簡單寫法
<bean id="user" class="com.pack.beans.User">
<property name="name" value="李四"/>
<property name="role" value="1,2"/>
<property name="myList" value="list1, list2"/>
<property name="mySet" value="set1, set2"/>
<property name="country" ref="china"/>
</bean>
域屬性自動注入
<bean id="id" class="class" autowire="xxx">
...
</bean>
byType去容器中找與屬性 類相同的bean來填充。bean必須唯一
byName 找與屬性名相同的bean來填充
SPEL注入
<bean id="user" class="com.pack.beans.User">
<property name="name" value="張三"/>
<property name="role" value="#{T(java.lang.Math).random() * 10}"/>
</bean>
<bean id="liming" class="com.pack.beans.User">
<property name="name" value="李四"/>
<property name="role" value="#{user.role}"/>
</bean>
調用方法
public Integer changeRole(){ if (name.equals("張三")){ return 12; } return role; }
<bean id="liming" class="com.pack.beans.User">
<property name="name" value="李四"/>
<property name="role" value="#{user.changeRole()}"/>
</bean>
要實現getter方法
多個配置文件
平行配置
有兩個配置文件 spring-1.xml 和 spring-2.xml
String resource = "spring-01.xml";
String resource2 = "spring-02.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(resource, resource2);
或者
String resource = "spring-01.xml"; String resource2 = "spring-02.xml"; String[] resources = {resource, resource2}; ApplicationContext ac = new ClassPathXmlApplicationContext(resources);
或者通配符模式
String resource = "spring-*.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
包含配置
<import resource="spring-user01.xml"/>
或者通配符模式
<import resource="spring-*.xml"/>
但是 主配置與子配置命名格式不能一樣
基于注解的DI
applicationContext.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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 掃描這個包及其子包-->
<context:component-scan base-package="com.anno.bean"/>
<!-- 掃描這個包的子包-->
<context:component-scan base-package="com.anno.*"/>
</beans>
@Scope("prototype") //默認
@Component("myUser")
public class User {
@Value("李四")
private String name;
@Value(value = "12")
private Integer age;
private Country country;
...
}
與@Component功能相同,但意義不同的注解還有三個
1)@Repository: 注解在Dao實現類
2)@Service: 注解在Service實現類
3)@Controller: 注解在SpringMVC的處理器上
AOP
Advice
前置通知
public class LogAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("log output"); } }
后置通知
可以獲得方法的返回值,但無法改變返回結果
public class LogAfterAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("After Log"); }
環(huán)繞通知
public class MMethodIntercept implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("before"); Object result = invocation.proceed(); System.out.println("after"); return result; } }
異常通知
public class MyThrowsAdvice implements ThrowsAdvice { public void afterThrowing(Exception ex){ //這里可以指定異常,當發(fā)生指定異常時,執(zhí)行指定的方法 // 方法名固定 System.out.println("exception occur"); } }
ApplicationContext.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.xsd http://www.springframework.org/schema/aop http://www.springframework.org//schema/spring-aop.xsd"> <bean id="myService" class="com.AOPLearn.Service.IServiceImpl"/> <bean id="myAdvice" class="com.AOPLearn.Proxy.MyThrowsAdvice"/> <bean id="myAdvice2" class="com.AOPLearn.Proxy.LogAfterAdvice"/> <bean id="myAdvice3" class="com.AOPLearn.Proxy.LogBeforeAdvice"/> <bean id="myAdvice4" class="com.AOPLearn.Proxy.MMethodIntercept"/> <bean id="enhencedService" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="targetName" value="myService"/> <property name="interceptorNames"> <array> <value>myAdvice</value> <value>myAdvice2</value> <value>myAdvice3</value> <value>myAdvice4</value> </array> </property> <!-- <property name="target" ref="myService"/>--> <!-- <property name="interfaces" value="com.AOPLearn.Proxy.LogAdvice"/>--> </bean> </beans>
IService service = (IService) ac.getBean("enhencedService");
service.doFirst();
此時service是jdk proxy, 想使用cglib proxy,只需把service,interface去掉,不使用接口便默認使用cglib
有接口默認使用jdk proxy,無接口默認使用cglib proxy
有借口時指定cglib的只需加入如下語句
<property name="proxyTargetClass" value="true"/>
或者
<property name="optimize" value="true"/>
Advisor
名稱匹配方法切入
<bean id="myAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <property name="advice" ref="myAdvice"/> <property name="mappedName" value="doFirst"/> //可以使用通配符 </bean>
正則匹配方法切入
<bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice" ref="myAdvice"/> <property name="pattern" value=".*doFirst"/> //正則表達式匹配的是全限定方法名 </bean>
默認自動代理生成器
由于 主業(yè)務(service)與(serviceProxy)存在耦合,還需解耦。
且 對于多個service 每個service方法都要注冊太冗余。需要使用自動代理生成器。
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/> //源碼分析后:xxCreator實現了bean后處理器,使得bean被初始化后,被enhence了
缺陷:
1)不能選擇目標對象。
2)不能選擇切面類型,切面只能是advisor。
3)不能選擇advisor,所有advisor都將被織入目標方法。
名稱自動代理生成器
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="myService"/>
<property name="interceptorNames" value="myAdvisor2"/>
</bean>
AspectJ Aop
<bean id="myAspect" class="com.AOPLearn.Proxy.MyAjProxy"/> <bean id="MyService" class="com.AOPLearn.AJ.BServiceImpl"/> <aop:aspectj-autoproxy/>
XML式
<aop:config>
<aop:aspect id="myAspect">
<aop:pointcut id="firstPC" expression="execution(* *..BService.doFirst(..))"/>
<aop:before method="myBefore" pointcut-ref="firstPC"/>
<aop:after-returning method="myAfterReturning" pointcut="execution(* *..BService.doSecond(..))"/>
<aop:around method="myAround" pointcut-ref="firstPC"/>
<aop:after-throwing method="myAfterThrowing" pointcut-ref="firstPC"/>
<aop:after method="myAfter" pointcut="execution(* *..BService.doFirst(..))"/>
</aop:aspect>
</aop:config>
注解式
@Aspect
public class MyAjProxy {
@Before(value = "execution(* *..BService.doFirst(..))")
public void before(JoinPoint jp){
System.out.println("before method jp " + jp);
}
@AfterReturning(value = "execution(* *..BService.doSecond(..))", returning = "result")
public void myAfterReturning(Object result){
System.out.println("after method result " +result);
}
@Around(value = "execution(* *..BService.doFirst(..))")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("before");
Object obj = pjp.proceed();
System.out.println("before");
return obj;
}
@AfterThrowing(value = "execution(* *..BService.doFirst(..))")
public void myAfterThrowing(){
System.out.println("exception occur");
}
@After(value = "doFirstPointcut()")
public void myAfter(){
System.out.println("final occur");
}
//指定 point點
@Pointcut("execution(* *..BService.doFirst(..))")
public void doFirstPointcut(){}
}
應用
DAO
spring中讀取配置信息
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="jdbc.properties"/>
</bean>
注冊數據源
<bean id="dataSourceJDBC" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/java?serverTimezone=GMT%2B8"/>
<property name="username" value="root"/>
<property name="password" value="baobao521"/>
</bean>
<bean id="dataSourceDBCP" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/java?serverTimezone=GMT%2B8"/>
<property name="username" value="root"/>
<property name="password" value="baobao521"/>
</bean>
<bean id="dataSourceC3P0" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/java?serverTimezone=GMT%2B8"/>
<property name="user" value="root"/>
<property name="password" value="baobao521"/>
</bean>
注冊JdbcTemplate
<bean id="jdbcTemplate1" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSourceJDBC"/>
</bean>
可以不注冊,保留一下或許有用
注冊dao
<bean id="userDao" class="com.SDAO.DAO.IUserDaoImpl">
<property name="dataSource" ref="dataSourceJDBC"/>
</bean>
實現dao層
public class IUserDaoImpl extends JdbcDaoSupport implements IUserDao {
@Override
public void insertUser(User user) {
String sql = "insert into user(username, password, role) values(?,?,?)";
this.getJdbcTemplate().update(sql, user.getUsername(),user.getPassword(), user.getRole());
}
@Override
public void deleteById(Integer id) {
String sql = "delete from user where id=?";
this.getJdbcTemplate().update(sql, id);
}
@Override
public void updateUser(User user) {
String sql = "update user set password=?,role=? where id=?";
this.getJdbcTemplate().update(sql, user.getPassword(), user.getRole(), user.getId());
}
@Override
public List<User> selectAll() {
String sql = "select * from user";
return this.getJdbcTemplate().query(sql, new UserRowMapper());
}
@Override
public User selectById(Integer id) {
String sql = "select * from user where id=?";
return (User) this.getJdbcTemplate().queryForObject(sql, new UserRowMapper(), id);
}
}
不能簡單的將JdbcTemplate抽取出來
JdbcTemplate是多實例的,即系統(tǒng)會為每一個模板線程創(chuàng)建一個JdbcTemplate實例,并在該線程結束時,自動釋放該實例。所以每次調用該實例時,都要通過getTemplate方法。
自定義類型查找操作需要RowMapper
public class UserRowMapper implements RowMapper { @Override public Object mapRow(ResultSet resultSet, int i) throws SQLException { User user = new User(); user.setId(resultSet.getInt("id")); user.setUsername(resultSet.getString("username")); user.setRole(resultSet.getInt("role")); return user; } }
Spring事務管理
PlatformTransactionManager接口兩個實現類
DataSourceTransactionManager 使用Jdbc 或 ibatis 進行持久化存儲時使用
HibernateTransactionManager 使用Hibernate時使用
5個事務隔離級別 //todo
7個事務傳播行為
REQUIRED 指定方法必須在事務下運行,沒有事務則創(chuàng)建事務
SUPPORTS 可以在事務下運行,也可以在非事務下運行
MANDATORY 必須在事務下執(zhí)行, 沒事務直接拋出異常
REQUIRED_NEW 總是新建一個事務來執(zhí)行方法
NOT_SUPPORTED 指定方法不能在事務環(huán)境下執(zhí)行,當前存在事務則將事務掛起
NEVER 指定方法不能在事務環(huán)境下執(zhí)行,當前存在事務則將拋出異常
NESTED 指定方法必須在事務下運行,有則在嵌套事務內運行,沒有則創(chuàng)建事務運行???
Spring事務的默認回滾方式 發(fā)生運行時異常回滾,發(fā)生受查異常提交。
XML式
注冊事務管理bean
<bean id="myTM" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceJDBC"/>
</bean>
<bean id="serviceProxy1" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="myTM"/>
<property name="target" ref="service1"/>
<property name="transactionAttributes">
<props>
<prop key="SB">-SBException</prop> //key 指定方法 -xxx 指定異常,受查異常默認提交
</props>
</property>
</bean>
AspectJ方式
<tx:advice id="txAdvice" transaction-manager="myTM">
<tx:attributes>
<tx:method name="SB" isolation="DEFAULT" propagation="REQUIRED" rollback-for="SBException"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="myPC1" expression="execution(* *..Service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="myPC1"/>
</aop:config>
注解式
xmlns:tx="http://www.springframework.org/schema/tx"
...
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
...
<tx:annotation-driven transaction-manager="myTM"/>
要添加事務的方法上加上以下語句
@Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED, rollbackFor = xxxException.class)
SpringWeb
applicationContext的注冊,在監(jiān)聽器中,可以實現在tomcat容器初始化時,使applicationContext單實例化。SpringWeb幫我們做好了這些
只需在web.xml中注冊
<listenner>
<listenner-class>org.springframework.web.context.ContextLoaderListenner</listenner-class>
</listenner>
制定配置文件的位置,默認情況下只能放在web-inf下
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:xxx.xml</param-value>
</context-param>
獲取Spring容器對象
WebApplicationContext ac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext);
//todo
浙公網安備 33010602011771號