赞
踩
/*带参数,方便利用构造器进行注入*/
public CatDaoImpl(String message){
this. message = message;
}
<bean id="CatDaoImpl" class="com.CatDaoImpl">
<constructor-arg value=" message "></constructor-arg>
</bean>
public class Id {
private int id;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
}
<bean id="id" class="com.id "> <property name="id" value="123"></property> </bean>
public class DaoFactory { //实例工厂 public FactoryDao getFactoryDaoImpl(){ return new FactoryDaoImpl(); } } public class SpringAction { private FactoryDao factoryDao; //注入对象 public void setFactoryDao(FactoryDao factoryDao) { this.factoryDao = factoryDao; } } <bean name="springAction" class="SpringAction"> <!--使用实例工厂的方法注入对象,对应下面的配置文件--> <property name="factoryDao" ref="factoryDao"></property> </bean> <!--此处获取对象的方式是从工厂类中获取实例方法--> <bean name="daoFactory" class="com.DaoFactory"></bean> <bean name="factoryDao" factory-bean="daoFactory" factory-method="getFactoryDaoImpl"> </bean>
Spring MVC:Spring的模型-视图-控制器,是围绕一个DispatcherServlet来设计的,这个servlet会把请求分发给各个处理器,并支持可以配置的处理器映射、视图渲染、本地化、时区与主题渲染等,甚至还能支持文件上传
为了保证数据库的正确性和一致性,事务具有四个特征
事务的传播行为(propagation behavior)指的是,一个事务方法被另外一个事务调用的时候,这个事务方法该如何进行
@Aspect @Component @Slf4j public class ConsoleLogAspect { //设置切面点(切面地址根据自己的项目填写) @Pointcut(value = "(execution(* com.xpos.stm.modules.sys.controller.*.*(..)))") public void webLog() {} //指定切点前的处理方法 @Before("webLog()") public void doBefore(JoinPoint joinPoint) throws Exception { //获取request对象 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); StringBuilder sb = new StringBuilder(); //拼接请求内容 sb.append("\n请求路径:" + request.getRequestURL().toString() + "\n"); sb.append("请求方式:" + request.getMethod() + "\n" ); sb.append("Encoding:" + request.getCharacterEncoding() + "\n" ); sb.append("请求的资源:" + request.getRequestURI() + "\n" ); sb.append("请求的URL地址中附带的参数:" +request.getQueryString()+ "\n" ); sb.append("请求内容:"+ JSON.toJSONString(joinPoint.getArgs())); log.info(sb.toString()); } //指定切点前的处理方法 @AfterReturning(pointcut = "webLog()",returning = "result") public void doAfterReturning(Object result) { if (ObjectUtils.isEmpty(result)){ return; } log.info("\n返回結果:" + JSON.toJSONString(result)); } }
<!--引入公共的配置文件--> <import resource="application-context.xml"/> <!--Spring提供的事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <constructor-arg ref="dataSource"/> </bean> <!-- 开启事务注解 这里有个小技巧,如果你的事务管理bean名不是transactionManager 就要给这个标签配置transaction-manager来指定 --> <tx:annotation-driven/> <!-- 配置spring扫描注解注入service类--> <context:component-scan base-package="cn.lyn4ever.service"/>
<import resource="application-context.xml"/> <!--Spring提供的事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <constructor-arg ref="dataSource"/> </bean> <tx:advice id="txAdvice"> <tx:attributes> <!-- 对单独方法配置属性--> <tx:method name="insert*" rollback-for="java.lang.Exception"/> <tx:method name="*"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="serviceTrans" expression="execution(* cn.lyn4ever.serviceaop.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceTrans"/> </aop:config> <!-- 配置spring扫描注解注入service类--> <context:component-scan base-package="cn.lyn4ever.serviceaop"/>
(1) 当对一个类标注@Component注解时,表明该类会作为组件类,spring将为这个类创建bean
(2) 当在应用文中引用这个bean,spring会自动扫描事先指定的包查找这个 bean。但spring默认是不启用组件扫描的,可以在XML中配置加上<context:component-scan base-package=“xx”/>。还有一种方法:在新建一个配置类,类中可以什么不用写,在配置类上加上@ComponentScan注解,spring会自动扫描改配置类所在的包,一般应该倾向xml配置
@Configuration
@ComponentScan
class Config {
}
(3) @Configuration注解表示是配置类,@ComponentScan注解能够在Spring中启用组件扫描,Spring会查找带有@Component注解的类,并会在Spring中自动为其创建一个bean
(4) @ContextConfiguration(classes=Config.class)表明了配置类的所在,这个Car类将会从Config配置类中获得扫描到的组件,然后通过@Autowired注解自动匹配,将bean注入给各个属性
interface Transportation { void run(); void stop(); } @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes=Config.class) public class Car implements Transportation { @Autowired private Wheel wheel; @Autowired private Seat seat; @Autowired private Engine engine; @Test public void run() { seat.seat(); engine.start(); wheel.roll(); System.out.println("The car has run."); } @Test public void stop() { System.out.println("Now, the car has stopped."); } }
(5) Autowired固然强大,但是如果有不止有一个bean能否匹配的话,就会阻碍自动装配。有两种处理方式:1. 表示首选的bean:只需要在组件类前面加一个@Primary注解即可,这样如果有多个bean匹配,就会先注入此组建类 2. 限定自动装配的bean:@Qualifier(“beanid”)注解
总结:实例化 -> 设置属性值 -> BeanNameAware -> BeanFactoryAware -> ApplicationContextAware -> BeanPostProcessor(postProcessBeforeInitialization) -> InitializingBean(afterPropertiesSet) -> init-method -> BeanPostProcessor(postProcessAfterInitialization) -> Destroy 过期自动清理阶段 -> destroy-method 自配置清理
(1) 编译时 Weaving: AspectJ 编译器作为输入我们的方面的源代码和我们的应用, 并产生一个织入类文件作为输出
(2)编译后 Weaving: 这也称为二进制织入。它是用来织入现有的类文件和 JAR 文件与我们的方面
(3)加载时间 Weaving: 这就像前二进制织入, 不同的是织入被推迟, 直到类加载程序加载类文件到 JVM
<!-- Spring MVC配置 --> <!-- ====================================== --> <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 可以自定义servlet.xml配置文件的位置和名称,默认为WEB-INF目录下,名称为[<servlet-name>]-servlet.xml,如spring-servlet.xml <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring-servlet.xml</param-value> 默认 </init-param> --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <!-- Spring配置 --> <!-- ====================================== --> <listener> <listenerclass> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <!-- 指定Spring Bean的配置文件所在目录。默认配置在WEB-INF目录下 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:config/applicationContext.xml</param-value> </context-param>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 加载配置文件 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 自动扫描web包 ,将带有注解的类纳入spring容器管理 --> <!--Spring 容器初始化的时候,会扫描 com.web 下标有 (@Component,@Service,@Controller,@Repository) 注解的类,纳入spring容器管理--> <context:component-scan base-package="com.web"></context:component-scan> <!-- dataSource 配置 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!-- 基本属性 url、user、password --> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="${jdbcUrl}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> <!-- 配置初始化大小 --> <property name="initialSize" value="1"/> <!-- 连接池最小空闲 --> <property name="minIdle" value="1"/> <!-- 连接池最大使用连接数量 --> <property name="maxActive" value="20"/> <!-- 配置获取连接等待超时的时间 --> <property name="maxWait" value="60000"/> <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> <property name="timeBetweenEvictionRunsMillis" value="60000"/> <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> <property name="minEvictableIdleTimeMillis" value="300000"/> </bean> <!--使用Spring+MyBatis的环境下,我们需要配值一个SqlSessionFactoryBean来充当SqlSessionFactory 在基本的MyBatis中,SqlSessionFactory可以使用SqlSessionFactoryBuilder来创建, 而在mybatis-spring中,则使用SqlSessionFactoryBean来创建。--> <!-- mybatis文件配置,扫描所有mapper文件 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" p:dataSource-ref="dataSource" p:configLocation="classpath:mybatis-config.xml" p:typeAliasesPackage="com.entity" <!-- 如果 MyBatis 映射器 XML 文件在和映射器类相同的路径下不存在,那么另外一个需要配置文件的原因就是它了。 --> p:mapperLocations="classpath*:mapper/*.xml"/> <!-- spring与mybatis整合配置,自动扫描所有dao ,将dao接口生成代理注入到Spring--> <!-- MapperScannerConfigurer 的作用是取代手动添加 Mapper ,自动扫描完成接口代理。 而不需要再在mybatis-config.xml里面去逐一配置mappers。 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" p:basePackage="com.dao" p:sqlSessionFactoryBeanName="sqlSessionFactory"/> <!-- 对dataSource 数据源进行事务管理 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource"/> <!-- 配置AOP通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- 配置事务属性 --> <tx:attributes> <!-- 添加事务管理的方法 --> <tx:method name="save*" propagation="REQUIRED"/> <tx:method name="delete*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="select*" propagation="REQUIRED" read-only="true"/> </tx:attributes> </tx:advice> <!-- 配置一个切面AOP --> <aop:config> <aop:aspect id="helloWorldAspect" ref="txAdvice"> <!-- 配置切点 --> <aop:pointcut id="pointcut" expression="execution(* com.aop.*.*(..))"/> <!-- 配置前置通知 --> <aop:before pointcut-ref="pointcut" method="beforeAdvice"/> <!-- 配置前置通知 --> <aop:after pointcut-ref="pointcut" method="afterAdvice"/> <!-- 配置后置返回通知 --> <aop:after-returning pointcut-ref="pointcut" method="afterReturnAdvice" returning="result"/> <!-- 配置环绕通知 --> <aop:around pointcut-ref="pointcut" method="aroundAdvice"/> <!-- 异常通知 --> <aop:after-throwing pointcut-ref="pointcut" method="throwingAdvice" throwing="e"/> </aop:aspect> </aop:config> <!-- 配置使Spring采用CGLIB代理 --> <aop:aspectj-autoproxy proxy-target-class="true"/> <!-- 启用对事务注解的支持 --> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context <a href="http://www.springframework.org/schema/context/spring-context-3.0.xsd">http://www.springframework.org/schema/context/spring-context-3.0.xsd</a>"> <!-- 启用spring mvc 注解 --> <context:annotation-config /> <!-- 设置使用注解的类所在的jar包 --> <context:component-scan base-package="controller"></context:component-scan> <!-- 完成请求和注解POJO的映射 --> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /> <!-- 对转向页面的路径解析。prefix:前缀, suffix:后缀 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/jsp/" p:suffix=".jsp" /> </beans>
Spring的启动过程其实就是IOC容器的启动过程
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/application_context.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
第4步中,代码在最后
(1)createWebApplicationContext(servletContext)方法即是完成创建WebApplicationContext工作,也就是说这个方法创建上下文对象支持用户自定义上下文对象,但必须继承ConfigurableWebApplicationContext,而Spring MVC默认使用ConfigurableWebApplicationContext作为ApplicationContext(它仅仅是一个接口)的实现
(2)configureAndRefreshWebApplicationContext就是用来加载spring配置文件中的Bean实例的。这个方法于封装ApplicationContext数据并且初始化所有相关Bean对象。它会从web.xml中读取名为 contextConfigLocation的配置,这就是spring xml数据源设置,然后放到ApplicationContext中
(3)最后调用传说中的refresh方法执行所有Java对象的创建
(4)最后完成ApplicationContext创建之后就是将其放入ServletContext中
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) { throw new IllegalStateException( "Cannot initialize context because there is already a root application context present - " + "check whether you have multiple ContextLoader* definitions in your web.xml!"); } Log logger = LogFactory.getLog(ContextLoader.class); servletContext.log("Initializing Spring root WebApplicationContext"); if (logger.isInfoEnabled()) { logger.info("Root WebApplicationContext: initialization started"); } long startTime = System.currentTimeMillis(); try { // Store context in local instance variable, to guarantee that // it is available on ServletContext shutdown. if (this.context == null) { this.context = createWebApplicationContext(servletContext); } if (this.context instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context; if (!cwac.isActive()) { // The context has not yet been refreshed -> provide services such as // setting the parent context, setting the application context id, etc if (cwac.getParent() == null) { // The context instance was injected without an explicit parent -> // determine parent for root web application context, if any. ApplicationContext parent = loadParentContext(servletContext); cwac.setParent(parent); } configureAndRefreshWebApplicationContext(cwac, servletContext); } } servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); ClassLoader ccl = Thread.currentThread().getContextClassLoader(); if (ccl == ContextLoader.class.getClassLoader()) { currentContext = this.context; } else if (ccl != null) { currentContextPerThread.put(ccl, this.context); } if (logger.isDebugEnabled()) { logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]"); } if (logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms"); } return this.context; } catch (RuntimeException ex) { logger.error("Context initialization failed", ex); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); throw ex; } catch (Error err) { logger.error("Context initialization failed", err); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err); throw err; }
总结:Spring 最初利用“工厂模式”(DI)和“代理模式”(AOP)解耦应用组件。大家觉得挺好用,于是按照这种模式搞了一个 MVC框架(一些用Spring 解耦的组件),用开发 web 应用( SpringMVC )。然后有发现每次开发都写很多样板代码,为了简化工作流程,于是开发出了一些“懒人整合包”(starter),这套就是 Spring Boot
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList(); this.configureHeadlessProperty(); SpringApplicationRunListeners listeners = this.getRunListeners(args); // 初始化监听器 listeners.starting(); Collection exceptionReporters; try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); this.configureIgnoreBeanInfo(environment); Banner printedBanner = this.printBanner(environment); context = this.createApplicationContext(); // 创建上下文实例 exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context); this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); this.refreshContext(context); this.afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } listeners.started(context); this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, exceptionReporters, listeners); throw new IllegalStateException(var10); } try { listeners.running(context); return context; } catch (Throwable var9) { this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null); throw new IllegalStateException(var9); } }
springboot默认扫描启动类所在的包下的主类与子类的所有组件,但并没有包括依赖包的中的类,那么依赖包中的bean是如何被发现和加载的?
@SpringBootApplication
public class StmApplication {
public static void main(String[] args) {
SpringApplication.run(StmApplication.class, args);
}
}
在Spring程序main方法中,添加@SpringBootApplication或者@EnableAutoConfiguration会自动去maven中读取每个starter中的spring.factories文件,该文件里配置了所有需要被创建的Spring容器中的bean
lazyLoadingEnabled=true|false
Mybatis有三种基本的Executor执行器,SimpleExecutor、ReuseExecutor、BatchExecutor
(1)Mybatis最上面是接口层,接口层就是开发人员在Mapper或者是Dao接口中的接口定义,是查询、新增、更新还是删除操作
(2)中间层是数据处理层,主要是配置Mapper -> XML层级之间的参数配置,SQL解析,SQL执行,结果映射的过程
(3)上述两种流程都是由基础支持层来提供功能支持,基础支持层包括连接管理、事务管理、配置加载、缓存处理等
InputStream is = Resources.getResourceAsStream("myBatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
sqlSession = factory.openSession();
SQL语句的执行涉及多个组件,包括Mybatis的四大核心,他们是Executor、StatementHandler、ResultHandler、ParameterHandler
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。