Tagged: Spring

Spring AOP

一、概念

AOP(Aspect Oriented Programming):面向切面编程。

面向切面编程(也叫面向方面编程),是目前软件开发中的一个热点,也是spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

二、用途

  • 日志记录
  • 性能统计
  • 安全控制
  • 权限管理
  • 事务处理
  • 异常处理
  • 资源池管理

三、详解

1. 切面(Aspect)

官方的抽象定义为“一个关注点的模块化,这个关注点可能会横切多个对象”,在本例中,“切面”就是类TestAspect所关注的具体行为,例如:AServiceImpl.barA()的调用就是切面TestAspect所关注的行为之一。“切面”在ApplicationContext中<aop:aspect>来配置。

2.连接点(Joinpoint)

程序执行过程中的某一行为,例如,AServiceImpl.barA()的调用或者BServiceImpl.barB(String _msg, int _type)抛出异常等行为。

3. 通知(Advice)

“切面”对于某个“连接点”所产生的动作,例如,TestAspect中对com.spring.service包下所有类的方法进行日志记录的动作就是一个Advice。其中,一个“切面”可以包含多个“Advice”,例如TestAspect。Advice共有如下5种类型:

  • 前置通知(Before advice) :
    在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。xml中在<aop:aspect>里面使用<aop:before>元素进行声明;例如,TestAspect中的doBefore方法。注解中使用@Before声明;例如,TestAnnotationAspect中的doBefore方法。
  • 后通知(After advice) :
    当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。xml中在<aop:aspect>里面使用<aop:after>元素进行声明。例如,TestAspect中的doAfter方法,所以AOPTest中调用BServiceImpl.barB抛出异常时,doAfter方法仍然执行。注解中使用@After声明。
  • 返回后通知(After return advice) :
    在某连接点正常完成后执行的通知,不包括抛出异常的情况。xml中在<aop:aspect>里面使用<after-returning>元素进行声明。注解中使用@AfterReturning声明;
  • 环绕通知(Around advice) :
    包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。xml中在<aop:aspect>里面使用<aop:around>元素进行声明。例如,TestAspect中的doAround方法。注解中使用@Around声明。
  • 抛出异常后通知(After throwing advice) :
    在方法抛出异常退出时执行的通知。xml中在<aop:aspect>里面使用<aop:after-throwing>元素进行声明。例如,TestAspect中的doThrowing方法。注解中使用@AfterThrowing声明。

通知执行顺序:前置通知→环绕通知连接点之前→连接点执行→环绕通知连接点之后→返回通知→(如果发生异常)异常通知→后通知
Read more

Spring/SpringMVC/MyBatis注解备忘录

Spring


@Autowired

自动装配,其作用是为了消除java代码里面的getter/setter与bean属性中的property。@Autowired默认按类型匹配的方式,在容器查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入@Autowired标注的变量中。

@Qualifier(指定注入Bean的名称)

如果一个容器有一个以上匹配的Bean,则可以使用@Qualifier注解限定Bean的名称。

@Resource

与@Autowired类似,默认通过name属性去匹配Bean,找不到再按type去匹配,指定了name或者type则根据指定类型去匹配Bean

@Service

标注业务层组件

@Controller

标注控制层组件

@Repository

标注数据访问层组件(即Dao组件)

@Component

泛指组件,当组件不好归类的时候,可以使用这个组件进行标注

@Configuration

把这个类作为一个Ioc容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。

@Scope

作用域(常用来设置该类是否为单例或多例)

@Lazy

表示延迟初始化(Spring默认是延迟加载,如果是工具类,则可以使用它来进行标注容器启动即实例化)

@PostConstruct

用于指定初始化方法(用在方法上)

@PreDestory

用于指定销毁方法(用在方法上)

@DependsOn

定义Bean初始化及销毁时的顺序

@Primary

自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常

@Async

异步方法调用

@EnableScheduling

开启对计划任务的支持

@EnableAspectJAutoProxy

激活Aspect自动代理

@EnableAsync

开启异步方法的支持

@EnableWebMVC

用来开启Web MVC的配置支持

@EnableConfigurationProperties

用来开启对@ConfigurationProperties注解配置Bean的支持

@EnableJpaRepositories

开启对Spring Data JPA Repostory的支持

@EnableTransactionManagement

注解开启注解式事务的支持

@EnableCaching

开启注解式的缓存支持

SpringMVC


@RequestMapping

处理请求地址映射,可用于类或者方法上

@PathVariable

获取Url中的动态参数

@RequestParam

将请求参数绑定到方法参数上

@RequestBody

将HTTP请求正文转换为适合的HttpMessageConverter对象

@ResponseBody

将内容或对象作为 HTTP 响应正文返回,并调用适合HttpMessageConverter的Adapter转换对象,写入输出流

@RestController

这个注解的类会被看作一个controller。controller中使用@RequestMapping的方法有一个默认的@ResponseBody注解。@ResponseBody也可以加到类一级,通过继承方法一级不需要添加。

@ModelAttribute

标明该方法的目的是添加一个或多个模型属性(Model attributes)。@ModelAttribute标注的方法会在@RequestMapping方法调用之前而调用

@SessionAttributes

将值放到Session作用域中,写在Class上面

@CookieValue

cookie 数据到处理器功能处理方法的方法参数上的绑定

@RequestHeader

请求头(header)数据到处理器功能处理方法的方法参数上的绑定

@ResponseStatus

定义处理器功能处理方法/异常处理器返回的状态码和原因

@ExceptionHandler

注解式声明异常处理器

MyBatis


@Insert

插入sql , 和xml insert sql语法完全一样

@Select

查询sql, 和xml select sql语法完全一样

@Update

更新sql, 和xml update sql语法完全一样

@Delete

删除sql, 和xml delete sql语法完全一样

@Param

入参

@Results

结果集合

@Result

结果

Spring整合Mybatis的集成方式

1、采用MapperScannerConfigurer,它将会查找类路径下的映射器并自动将它们创建成MapperFactoryBean。

<?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"
	   xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

	<!-- 自动扫描注解,管理bean -->
	<context:component-scan base-package="com.pay.service">
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
	</context:component-scan>

	<context:component-scan base-package="com.pay.model,com.pay.dto">
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
	</context:component-scan>

	<!-- 1.1 加载数据库配置文件 -->
	<context:property-placeholder location="classpath:jdbc.properties"/>

	<!--开启注解方式-->
	<context:annotation-config/>

	<!-- 1.2 配置Druid数据源 -->
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
		<!-- 配置连接池属性 -->
		<property name="driverClassName" value="${jdbc.driver}"/>
		<property name="url" value="${jdbc.url}"/>
		<property name="username" value="${jdbc.username}"/>
		<property name="password" value="${jdbc.password}"/>

		<!-- 配置初始化大小、最小、最大 -->
		<property name="initialSize" value="${initialSize}"/>
		<property name="minIdle" value="${minIdle}"/>
		<property name="maxActive" value="${maxActive}"/>

		<!-- 配置获取连接等待超时的时间 -->
		<property name="maxWait" value="60000"/>

		<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
		<property name="timeBetweenEvictionRunsMillis" value="60000"/>

		<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
		<property name="minEvictableIdleTimeMillis" value="300000"/>
		<property name="validationQuery" value="SELECT 'x'"/>
		<property name="testWhileIdle" value="true"/>
		<property name="testOnBorrow" value="false"/>
		<property name="testOnReturn" value="false"/>

		<!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
		<property name="poolPreparedStatements" value="true"/>
		<property name="maxPoolPreparedStatementPerConnectionSize" value="20"/>

		<!-- 配置监控统计拦截的filters,去掉后监控界面sql无法统计 -->
		<property name="filters" value="stat"/>
	</bean>

	<!-- 1.3 Spring和MyBatis整合,配置sqlSessionFactory -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<!-- 数据库连接池 -->
		<property name="dataSource" ref="dataSource"/>
		<!-- 配置 Mybatis 全局配置文件 -->
		<property name="configLocation" value="classpath:/config/mybatis-config.xml"/>
		<!-- 自动扫描mapping.xml文件 -->
		<property name="mapperLocations" value="classpath:/mapper/*.xml"/>
		<!--<property name="typeAliasesPackage" value="com.pay.model"/>-->
	</bean>

	<!-- 1.4 扫描Dao接口,Spring会自动查找其下的类,注入到spring容器中 包下的类需要使用@MapperScan注解-->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<!-- 扫描包路径,如果需要扫描多个包,中间使用半角逗号分割 -->
		<property name="basePackage" value="com.pay.dao"/>
		<property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/>
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
	</bean>

	<!-- 启用sqlSessionTemplate来执行session的执行操作 -->
	<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg ref="sqlSessionFactory"/>
	</bean>

	<!-- 工具类 -->
	<bean id="beanFactoryUtil" class="com.pay.util.BeanFactoryUtil" lazy-init="false"/>

	<!-- druid 日志 -->
	<bean id="logFilter" class="com.alibaba.druid.filter.logging.Slf4jLogFilter">
		<property name="statementExecutableSqlLogEnable" value="true"/>
	</bean>

	<!-- 事务管理 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"/>
	</bean>

	<!-- 配置事务的注解方式注入,开启对Class的动态代理功能 -->
	<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

	<!-- 通知 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<!-- 传播行为 -->
			<tx:method name="save*" propagation="REQUIRED"/>
			<tx:method name="insert*" propagation="REQUIRED"/>
			<tx:method name="add*" propagation="REQUIRED"/>
			<tx:method name="create*" propagation="REQUIRED"/>
			<tx:method name="delete*" propagation="REQUIRED"/>
			<tx:method name="update*" propagation="REQUIRED"/>
			<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
			<tx:method name="select*" propagation="SUPPORTS" read-only="true"/>
			<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
		</tx:attributes>
	</tx:advice>
	<!-- 切面 -->
	<aop:config>
		<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.pay.service.*.*(..))"/>
	</aop:config>

</beans>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.pay.dao.IManagerDao">

  <!-- 缓存配置 -->
  <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>

  <resultMap id="ManagerResultMap" type="com.pay.model.Manager">
    <constructor>
      <idArg column="id" javaType="java.lang.Integer" jdbcType="INTEGER" />
      <arg column="userName" javaType="java.lang.String" jdbcType="VARCHAR" />
      <arg column="userPwd" javaType="java.lang.String" jdbcType="VARCHAR" />
      <arg column="email" javaType="java.lang.String" jdbcType="VARCHAR" />
    </constructor>
  </resultMap>
  <sql id="ManagerList">
    id, userName, userPwd, email
  </sql>

  <!-- 添加管理员 -->
  <insert id="add" parameterType="com.pay.model.Manager">
    insert into manager (userName, userPwd, email)
    values (#{username,jdbcType=VARCHAR}, #{userpwd,jdbcType=VARCHAR},
      #{email,jdbcType=VARCHAR})
  </insert>

  <!-- 删除管理员 -->
  <delete id="del" parameterType="Integer">
    DELETE from manager where id = #{id}
  </delete>

  <!-- 查询管理员 -->
  <select id="findUser" resultMap="ManagerResultMap">
    select <include refid="ManagerList"/> from manager where userName = #{userName} and userPwd = #{userPwd}
  </select>

  <select id="findAll" resultMap="ManagerResultMap" >
    SELECT * from manager
  </select>

  <!-- 更改管理员密码 -->
  <update id="updatePwd" parameterType="com.pay.model.Manager">
    UPDATE manager SET userPwd = #{userPwd} where userName = #{userName} and id = #{id}
  </update>

</mapper>
package com.pay.dao;

import com.pay.model.Manager;
import org.apache.ibatis.annotations.Param;
import org.mybatis.spring.annotation.MapperScan;

import java.util.List;

@MapperScan
public interface IManagerDao {
    /**
     * 添加一个管理员
     * @param bean 管理实体类
     */
    int add(Manager bean);

    /**
     * 查询管理用户
     * @param userName 用户名
     * @param userPwd 用户密码
     * @return 一个管理角色对象
     */
    Manager findUser(@Param("userName") String userName, @Param("userPwd") String userPwd);

    /**
     * 更改管理员密码
     * @param userName 用户名
     * @param newPwd 用户新密码
     */
    void updatePwd(String userName, String newPwd);

    /**
     * 查询所有管理员用户
     * @return 管理员集合
     */
    List<Manager> findAll();
}
package com.pay.service;

import com.pay.model.Manager;

import java.util.List;

/**
 * 管理员业务层
 * @author jalena
 *
 */
public interface IManagerService {
	/**
	 * 添加一个管理员
	 * @param bean 管理实体类
	 */
	int add(Manager bean);
	
	/**
	 * 查询管理用户
	 * @param userName 用户名
	 * @param userPwd 用户密码
	 * @return 一个管理角色对象
	 */
	Manager findUser(String userName, String userPwd);
	
	/**
	 * 更改管理员密码
	 * @param userName 用户名
	 * @param newPwd 用户新密码
	 */
	void updatePwd(String userName, String newPwd);
	
	/**
	 * 查询所有管理员用户
	 * @return 管理员集合
	 */
	List<Manager> findAll();
}
package com.pay.service.impl;

import com.pay.dao.IManagerDao;
import com.pay.model.Manager;
import com.pay.service.IManagerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author Jalena
 * @create 2017-04-09 23:20
 */
@Service
@Transactional
public class IManagerServiceImpl implements IManagerService {

	@Autowired
	private IManagerDao dao;

	public int add(Manager bean) {
		return dao.add(bean);
	}

	public Manager findUser(String userName, String userPwd) {
		return dao.findUser(userName,userPwd);
	}

	public void updatePwd(String userName, String newPwd) {
		dao.updatePwd(userName,newPwd);
	}

	public List<Manager> findAll() {
		return dao.findAll();
	}
}

这种方式最好!

Read more

Spring MVC 启动后执行方法

以前在Servlet里面我们都是重写httpServlet的init方法来达到,在Spring里面我们只需要配置一下就能达到目的

<!--注意:lazy-init="false" init-method="init" -->
<bean id="cacheLoder" lazy-init="false" class="CacheLoder" init-method="init" />

获取Spring Bean的几种方式

  1. 在初始化时保存ApplicationContext对象
  2. 通过spring提供的utils类获取ApplicationContext对象
  3. 继承自抽象类ApplicationObjectSupport
  4. 继承自抽象类WebApplicationObjectSupport
  5. 实现接口ApplicationContextAware
  6. 通过Spring提供的ContextLoader

方法1.

说明:这种方式适用于采用Spring框架的独立应用程序,需要程序通过配置文件手工初始化Spring的情况。

ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml"); 
ac.getBean("beanId");

方法2.通过Spring提供的工具类获取ApplicationContext对象

说明:这种方式适合于采用Spring框架的B/S系统,通过ServletContext对象获取ApplicationContext对象,然后在通过它获取需要的类实例。上面两个工具方式的区别是,前者在获取失败时抛出异常,后者返回null。

ApplicationContext ac1 = WebApplicationContextUtils.getRequiredWebApplicationContext(ServletContext sc); 
ApplicationContext ac2 = WebApplicationContextUtils.getWebApplicationContext(ServletContext sc); 
ac1.getBean("beanId"); 
ac2.getBean("beanId");

方法3.继承自抽象类ApplicationObjectSupport

说明:抽象类ApplicationObjectSupport提供getApplicationContext()方法,可以方便的获取ApplicationContext。
Spring初始化时,会通过该抽象类的setApplicationContext(ApplicationContext context)方法将ApplicationContext 对象注入。

方法4.继承自抽象类WebApplicationObjectSupport

说明:类似上面方法,调用getWebApplicationContext()获取WebApplicationContext

方法5.实现接口ApplicationContextAware

说明:实现该接口的setApplicationContext(ApplicationContext context)方法,并保存ApplicationContext 对象。Spring初始化时,会通过该方法将ApplicationContext对象注入。

package com.pay.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * Spring Bean工具类
 *
 * @author Jalena
 * @create 2017-05-08 23:25
 */
@Component
public class BeanFactoryUtil implements ApplicationContextAware {

	public BeanFactoryUtil() {
	}

	// spring 上下文对象
	private static ApplicationContext applicationContext;

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}

	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}


	/**
	 * 根据类唯一标识名获取Bean
	 * @param beanName 唯一标识名称(ID)
	 * @return Object
	 * @throws BeansException
	 */
	public static Object getBeanByName(String beanName) throws BeansException{
		return applicationContext.getBean(beanName);
	}

	/**
	 * 根据类Class获取Bean
	 * @param requiredType 类Class
	 * @param <T> 类型
	 * @return
	 * @throws BeansException
	 */
	public static <T> T getBeanByClass(Class<T> requiredType) throws BeansException{
		return applicationContext.getBean(requiredType);
	}

	/**
	 * 根据类唯一标识名及类Class获取Bean
	 * @param beanName 唯一标识名
	 * @param requiredType 类Class
	 * @param <T> 类型
	 * @return
	 * @throws BeansException
	 */
	public static <T> T getBeanByNameAndClass(String beanName, Class<T> requiredType) throws BeansException {
		return applicationContext.getBean(beanName, requiredType);
	}
}

方法6.通过Spring提供的ContextLoader

WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
wac.getBean(beanID);

 

Eclipse 安装Spring IDE支持

ECLIPSE ARCHIVE 离线安装包 SIZE
4.6 springsource-tool-suite-3.8.1.RELEASE-e4.6-updatesite.zip 146MB
4.5.2 springsource-tool-suite-3.8.1.RELEASE-e4.5.2-updatesite.zip 146MB
ECLIPSE UPDATE SITES 在线安装包
4.6 http://dist.springsource.com/release/TOOLS/update/e4.6/
4.5 http://dist.springsource.com/release/TOOLS/update/e4.5/

Spring Tool Suite™ Downloads

安装方法

  1. 获取当前使用的Eclipse版本
  2. 如果选择压缩包安装就先下载对应的安装包,如果选择链接下载就先将链接复制过来,然后 Eclipse -> Help -> Install Software  -> Add
  3. 下面就简单了,根据操作允许许可协议就好 了。
  4. 推荐使用离线安装包安装,使用在线安装容易造成安装报错(有几个大的jar包如果长时间不动,会造成超时,那么安装就会失败!)