初始Spring(适合新手)

一、Spring核心概念(IOC)

控制反转IOC:Inversion of control 控制对象产生的权利反转到spring ioc 依赖注入DI:Dependency injection 依赖spring ioc注入对象

  1. 最少jar包: spring-beans-.jar spring-context- .jar spring-core-.jar spring-expression- .jar spring-aop-.jar(4.0以上) commons-logging-.jar(apache struts)

  2. 配置applicationContext.xml(Eclipse自动生成配置文件需要安装Spring Tools插件)

  3. Spring注入:set注入、p注入、构造注入

    采用p:属性='值' or p:属性-ref=''方式注入(引入头7.4.2) <bean id='' class='' p:person="张嘎"/>

    <bean>中的name属性和id属性一样,直接属性值注入:value,引用注入:ref

    bean的生存范围:scope 属性 默认singleton 其他:prototype(原型)、(WEB)request session application...

    自动注入autowire: 单个配:在<bean/>中配autowire(byName,byType:只能有1个类型匹配才行,如果两个同类型则异常,对注解同样有效) 配全局:在<beans/>中配default-autowire="byName",默认是no

    bean生命周期:(只适用于singleton;prototype的生命周期容器不能控制也就是不执行销毁)

    lazy-init(也分局部和全局),init-method="方法名"、destroy-method="方法名" 要使destroy-method执行使用:ApplicationContext接口的实现类AbstractApplicationContext ctx = ... ctx.destroy();|ctx.close();

  4. 集合注入:查文档collections List、Set、Map、Properties

  5. 注解方式annotation: 1、配置xml的context头 <context:annotation-config> (可选,被componet-scan集成) <context:component-scan base-package="com.cssl"/>(必须有) 2、@Component, @Repository, @Service, @Controller效果一样,默认id为类名首字母小写 3、@Autowired 默认是byType,找到多个类型匹配的,则按byName注入,如果还找不到bean,则异常 4、多个类型在属性上或set方法或方法参数前加 @Qualifier("id的名称") 5、@Resource 默认是byName,没有则按byType,byType又有多个则异常 6、@PostConstruct(相当init-method) and @PreDestroy(相当destroy-method) 7、@Scope("prototype") 8、@Value("")注入固定值 9、集合注入,spring会自动将所有bean注入集合,map的key为bean的id

java 复制代码
@Autowired
List<UsersDao> list;	
@Autowired
Map<String, UsersDao> map;

注解可以不写set方法直接写到属性上


二、Spring核心概念(AOP)
  1. AOP:Aspect Oriented Programming

    引入 aspectjweaver 和 aopalliance 两个jar包

    AOP 领域中的特性术语:

    • 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。

    • 连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。

    • 切点(PointCut): 可以插入增强处理的连接点。

    • 切面(Aspect): 切面是通知和切点的结合。

    • 引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。

    • 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。

    概念看起来总是有点懵,并且上述术语,不同的参考书籍上翻译还不一样,所以需要慢慢在应用中理解。

    AspectJ语法:?代表0或1次 *代表任意 execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)

java 复制代码
modifiers-pattern:方法的访问修饰
ret-type-pattern:返回值 * 
declaring-type-pattern:方法所在的包及类 *
name-pattern:方法名 *
param-pattern:参数名 ..
throws-pattern:异常

execution(public * com.cssl.service..*.add(..))

  1. Annotation配置: 无接口的类被代理的情况下直接转二进制(cglib,Spring3.2以上已经集成此包) 测试类名可以得出结论:(service.getClass())

1、xml中必须加aop:aspectj-autoproxy/ 2、类上加@Component、@Aspect(切面逻辑) 3、织入方法上写@Before("execution(public void com.cssl...(com.pojo.Users))") 4、也可以使用@AfterReturning|@After|@Around|@AfterThrowing 5、@AfterReturning只有方法没有抛出异常的情况下执行,不管是否有返回值 6、切面类上加@Order(1)决定切面执行顺序

注意: 1、Spring提供的环绕处理类: ProceedingJoinPoint(不能使用父接口JoinPoint,接口没有proceed()方法)

java 复制代码
public void around(ProceedingJoinPoint pjp) throws Throwable{
	... 	
	//这里如果异常是自己处理了则@AfterThrowing捕获不到service方法抛出的异常
	pjp.proceed();	
	...
}

2、@AfterThrowing要起作用必须是该Pointcut方法上抛出的异常,不能方法里处理

java 复制代码
@AfterThrowing(pointcut="cut()",throwing="e")
public void doException(Exception e) {
	System.out.println("出异常咯:"+e.getMessage());		
}

3、写通用切入点方法:

java 复制代码
@Pointcut("execution(public * com.cssl..*.*(..))")
public void cutAll(){};

4、其他方法引入该切入点11.2.4

java 复制代码
@Before("cutAll()") || @Before("Logger.cutAll()")
public void before(){}

5、拦截含有参数的方法,并将参数值注入到当前方法的形参id,name中

java 复制代码
@Before("cutAll() && args(id,name)")
public void before(int id,String name)
public void before(JoinPoint jp):jp.getArgs() 

6、获取被切入方法的返回值

java 复制代码
@AfterReturning(pointcut="cutAll()",returning="result")
public void afterReturn(JoinPoint jp,Object result)

xml配置:在切面逻辑是第三方提供的情况下只能使用xml

XML 复制代码
<!-- order不写默认是最大值 -->
<aop:config>
  <aop:pointcut expression="execution(* com.cssl.service..*.add(..))" id="cutAll"/>
  <aop:aspect ref="logInfo">
     <aop:before method="before" pointcut="execution(public * com..*.*(int)) and args(id)" />    	
     <aop:after-returning method="afterReturn" pointcut-ref="cutAll" returning="result"/>
  </aop:aspect>
</aop:config>

Spring的AOP实现:4种(没有AfterAdvice)

  • MethodBeforeAdvice 前置通知: 在某连接点JoinPoint之前执行的通知,但这个通知不能阻止连接点前的执行。

  • AfterReturningAdvice 返回后通知:在某连接点正常完成后执行的通知,不包括抛出异常的情况。

  • MethodInterceptor(导入aopalliance包的接口) 环绕通知: 包围一个连接点的通知,类似Web中的Filter的doFilter方法。

  • ThrowsAdvice 异常通知: 在方法抛出异常退出时执行的通知。 必须使用下面的方法签名:(Throwable e必须有,而且方法可以写多个) public void afterThrowing([Method method, Object[] arguments, Object target,] Throwable ex)

使用:(注意advice-ref引用的bean必须是Advice接口的实现类)

XML 复制代码
<aop:config>
  <aop:pointcut expression="execution(public * com.cssl.service..*.*(..))" id="cut"/>
  <aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="cut"/>
</aop:config>
  1. Filter和Interceptor都应用了面向切面编程思想
三、Spring整合MyBatis

spring包:spring-jdbc-x.x.x.jar、spring-tx-x.x.x.jar spring整合mybatis:导包mybatis-spring-x.x.x.jar (MyBatis3.4+需要1.3+以上版本)

DataSource: 使用属性配置文件:占位符的方式(${这里绝对不要多加空格})

XML 复制代码
<bean id="ppc" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<property name="locations" value="classpath:jdbc.properties"/>
</bean>

也可以配置:

XML 复制代码
<context:property-placeholder location="classpath:mysql.properties"/>

如果不能识别${},不要配置default-autowire,或者修改属性ignore-unresolvable="true"

XML 复制代码
<!-- 纯jdbc数据源:不同MyBatis这里${}必须有前缀,加什么前缀都可以 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	<property name="driverClassName" value="${jdbc.driverClassName}"/>
	<property name="url" value="${jdbc.url}"/>
	<property name="username" value="${jdbc.username}"/>
	<property name="password" value="${jdbc.password}"/>
</bean>

<!-- sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">	
	<property name="dataSource" ref="dataSource" />	
	<property name="configLocation" value="classpath:mybatis-config.xml"/>
	<!-- 或者 -->
	<property name="mapperLocations" value="classpath:com/cssl/dao/*.xml"/>	
	<property name="typeAliasesPackage" value="com.cssl.pojo"/>	
</bean>

<!-- 为每一个dao生成对应的id,一定要注入sqlSessionFactory -->
<bean id="studentDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
	<property name="mapperInterface" value="com.cssl.dao.StudentDao"/>
	<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>	

<!--或者使用扫描包下所有接口-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	<property name="basePackage" value="com.cssl.dao"/>
	<!-- sqlSessionFactory可以被自动注入,如果加入下面配置dataSource不能${} -->
	<!--<property name="sqlSessionFactory" ref="sqlSessionFactory"/>-->
	<!--<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>-->
</bean>

注意: 1、sqlSessionFactory可以不用注,自动将dao包下接口根据接口名第一个字母小写生成id名 2、如果使用了default-autowire="byName...",DataSource必须使用字符串常量(不要使用自动注入)

事务管理:默认catch到RuntimeException回滚:(对于手动处理的异常spring不再管理)

XML 复制代码
<!-- JDBC不加事务每个dao方法都是一个事务,所以我们必须改变事务边界到service -->
<bean id="tx"    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	 <property name="dataSource" ref="dataSource"/>
</bean>

<tx:advice id="txAdvice" transaction-manager="tx">
	<tx:attributes>
		<tx:method name="exists" read-only="true" />
		<tx:method name="add*" propagation="REQUIRED"/>
		<tx:method name="*" read-only="true"
          		rollback-for="DataAccessException"
          		no-rollback-for="NullPointerException,ClassCastException" />
	</tx:attributes>
</tx:advice>

<aop:config>
	<aop:pointcut id="bussinessService" expression="execution(public * com.cssl.service..*.*(..))" />
	<aop:advisor pointcut-ref="bussinessService" advice-ref="txAdvice" />
</aop:config>

事务隔离级别:read-uncommited read-commited repeatable-read serializable

注意:

  • MyBatis没有事务默认每一条sql是一个事务! readOnly:true|false 用于查询提高效率和防止意外插入、删除、更新操作 (MyBatis操作Oracle数据库时增删改也能提交,会自动修改其为false) timeout :事务超时时间(单位秒),有的数据库事务不支持

  • Propagation: REQUIRED:业务方法需要在一个事务里运行。如果方法运行时,已经处在一个事务中,那么加入到这个事务,否则自己新建一个新的事务。

  • REQUIRES_NEW:不管是否存在事务,该方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务挂起(暂停),新的事务被创建。

  • NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中。它是已经存在事务的一个真正的子事务,如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的savepoint。内部事务的回滚不会对外部事务造成影响。 嵌套事务是外部事务的一部分, 只有外部事务结束后它才会被提交。

  • Annotation事务: <tx:annotation-driven transaction-manager="txManager"/> 类或方法前加@Trasactional @Transactional(transactionManager="txManager",isolation=Isolation.READ_COMMITTED)


四、JdbcTemplate回调机制(模版方法设计模式)及其他数据源配置

SqlSessionTemplate,HibernateTemplate,JpaTemplate RedisTemplate,MongoTemplate,SolrTemplate,JmsTemplate,RabbitTemplate

  1. 项目大拆分配置文件: 1、分层配置dao|service|controller 2、按模块配置 3、<import resource="xxx.xml"/>导入其他配置 4、new ClassPathXmlApplicationContext({"dao.xml","service.xml"});

  2. Spring+JDBC: queryForXXX()|query()

XML 复制代码
<bean id="template" class="org.springframework.jdbc.core.JdbcTemplate">
	<property name="dataSource" ref="dataSource"/>
</bean>
java 复制代码
Users u = template.queryForObject(sql,new BeanPropertyRowMapper<Users>(Users.class));
List<Users> users = template.query(sql,new BeanPropertyRowMapper<Users>(Users.class));

String sql = "select name from users";		
String name = template.queryForList(sql, String.class);

String sql = "select * from users";
List<Map<String, Object>> list = template.queryForList(sql);

//调用存储过程 demo  不能用lambda
this.template.execute("{call demo(?,?)}", new CallableStatementCallback<Object>() {
	@Override
	public Object doInCallableStatement(CallableStatement cs)
		throws SQLException, DataAccessException {
		...
		return out;
	}
});
  1. 其他数据源配置: 使用dbcp连接池:导commons-dbcp-x.x.jar和commons-pool-x.x.jar
XML 复制代码
<!-- dbcp数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" /> 
    <property name="password" value="${jdbc.password}" />
    <property name="maxActive" value="100" />
    <property name="maxIdle" value="30" />
    <property name="maxWait" value="3000" /> 拿到连接3秒不用自动被容器回收
</bean>

<!-- dbcp2(Tomcat8.5+) -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
    <property name="maxTotal" value="100" />
    <property name="maxIdle" value="30" />
    <property name="maxWaitMillis" value="3000" />
</bean>

<!--C3P0连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">	
	<property name="driverClass" value="${jdbc.driverClassName}"/>	
	<property name="jdbcUrl" value="${jdbc.url}"/>	
	<property name="user" value="${jdbc.username}"/>	
	<property name="password" value="${jdbc.password}"/>	
	<property name="maxPoolSize" value="30"/>	<!-- 连接池的最大连接数 -->	
	<property name="minPoolSize" value="3"/>	<!-- 连接池的最小连接数 -->	
	<property name="initialPoolSize" value="1"/>	<!-- 连接池的初始化连接数 -->	
	<property name="maxIdleTime" value="20"/>	<!-- 连接池的连接最大空闲时间 -->
</bean>

<!--阿里巴巴数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"
      p:driverClassName="${jdbc_driverClassName}"
      p:url="${jdbc_url}"
      p:username="${jdbc_username}"
      p:password="${jdbc_password}"         
      p:maxActive="50"
      p:initialSize="1"
      p:maxWait="100"
      p:maxIdle="20"
      p:minIdle="3"       
      p:connectionProperties="clientEncoding=UTF-8">
</bean>

<!--JNDI Java Naming and Directory Interface (使用tomcat作为实例)-->
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
	//代表命名服务目录名称为jdbc/mysql(实际为:java:comp/env/jdbc/mysql)
	<property name="jndiName" value="jdbc/mysql"/>
	//加上这个的意思是不用使用java:comp/env/来设置jndiName
	<property name="resourceRef" value="true"/>
</bean>

<!--或者使用:(导入jee命名空间)-->
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/news" resource-ref="true" />
相关推荐
Re.不晚4 分钟前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea
雷神乐乐10 分钟前
Maven学习——创建Maven的Java和Web工程,并运行在Tomcat上
java·maven
码农派大星。13 分钟前
Spring Boot 配置文件
java·spring boot·后端
顾北川_野20 分钟前
Android 手机设备的OEM-unlock解锁 和 adb push文件
android·java
江深竹静,一苇以航22 分钟前
springboot3项目整合Mybatis-plus启动项目报错:Invalid bean definition with name ‘xxxMapper‘
java·spring boot
confiself38 分钟前
大模型系列——LLAMA-O1 复刻代码解读
java·开发语言
Wlq041543 分钟前
J2EE平台
java·java-ee
XiaoLeisj1 小时前
【JavaEE初阶 — 多线程】Thread类的方法&线程生命周期
java·开发语言·java-ee
杜杜的man1 小时前
【go从零单排】go中的结构体struct和method
开发语言·后端·golang
幼儿园老大*1 小时前
走进 Go 语言基础语法
开发语言·后端·学习·golang·go