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 ac = new ClassPathXmlApplicationContext("applicationContext.xml"); IService service = (IService) ac.getBean("myService"); service.getService();
ApplicationContext ac = new FileSystemXmlApplicationContext();
IService service = (IService) ac.getBean("H:\\Program\\WorkSpace\\Java\\SpringLearn\\src\\applicationContext.xml");
service.getService();
已废用
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); IService service = (IService) bf.getBean("myService"); service.getService();
ApplicationContext 在容器初始化时,会将所有的bean创建
优点:响应快
缺点:占用资源
BeanFactory,在真正使用bean时才创建
优点:不多占用系统资源
缺点:响应慢
相较于资源占用,我们一般选择响应速度快的ApplicationContext
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();
<bean id="myService" class="com.pack.Service.ServiceFactory" factory-method="getService"/>
ServiceFactory
public class ServiceFactory { public static IService getService(){ return new IServiceImpl(); } }
<bean id="myService" class="com.pack.Service.ServiceFactory" factory-method="getService" scope="prototype"/>
scope 为bean的管理有singleton prototype request session
其对象的创建时机不是在初始化时,而是在访问时
singleton是默认方式,创建在初始化时。
request 对于一个Http请求,创建一次
session 对于每一个Http-Session, 创建一次
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: 执行Bean前处理"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("Step8: 执行Bean后处理"); return bean; } }
Step1: 构造器 step2: setter() Step3: BeanNameAware 获取beanNamemyService BeanFactoryAware Step4: 获取beanFactory step5: 执行Bean前处理 InitializingBean Step 6: bean初始化完毕 Step7: bean初始化之后 Step8: 执行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("执行Bean前处理"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("执行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; } }
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来填充
<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"/>
但是 主配置与子配置命名格式不能一样
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的处理器上
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"); }
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){ //这里可以指定异常,当发生指定异常时,执行指定的方法 // 方法名固定 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"/>
<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>
由于 主业务(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>
<bean id="myAspect" class="com.AOPLearn.Proxy.MyAjProxy"/> <bean id="MyService" class="com.AOPLearn.AJ.BServiceImpl"/> <aop:aspectj-autoproxy/>
<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(){}
}
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是多实例的,即系统会为每一个模板线程创建一个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; } }
PlatformTransactionManager接口两个实现类
DataSourceTransactionManager 使用Jdbc 或 ibatis 进行持久化存储时使用
HibernateTransactionManager 使用Hibernate时使用
REQUIRED 指定方法必须在事务下运行,没有事务则创建事务
SUPPORTS 可以在事务下运行,也可以在非事务下运行
MANDATORY 必须在事务下执行, 没事务直接抛出异常
REQUIRED_NEW 总是新建一个事务来执行方法
NOT_SUPPORTED 指定方法不能在事务环境下执行,当前存在事务则将事务挂起
NEVER 指定方法不能在事务环境下执行,当前存在事务则将抛出异常
NESTED 指定方法必须在事务下运行,有则在嵌套事务内运行,没有则创建事务运行???
Spring事务的默认回滚方式 发生运行时异常回滚,发生受查异常提交。
注册事务管理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)
applicationContext的注册,在监听器中,可以实现在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
原文:https://www.cnblogs.com/wrnmb/p/10729725.html