spring基于AspectJ方式的注解开发
开发实例
引入jar包
引入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:aop="http://www.springframework.org/schema/aop"
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/aop/spring-aop.xsd">
<!--将增强类交给spring管理-->
<bean id="user" class="com.dao.impl.UserDaoImpl"></bean>
<!--将切面类交给spring管理-->
<bean id="myAspectAnno" class="com.domain.MyAspectAnno"></bean>
<!--使用基于AspectJ方式的注解方式的开发-->
<!--在配置文件中开启注解方式的开发-->
<aop:aspectj-autoproxy />
</beans>
创建要增强的User.java类,并在配置文件中配置
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("保存用户!!");
}
@Override
public String find() {
System.out.println("查找用户");
return "哈哈哈";
}
@Override
public void delete() {
int a;
a=2/0;
System.out.println("删除用户");
}
@Override
public void update() {
System.out.println("更新用户");
}
}
创建切面类,并在配置文件中配置,在切面类中使用AOP注解
package com.domain;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import java.beans.Transient;
@Aspect
public class MyAspectAnno {
//前置通知
@Before(value = "execution(* com.dao.impl.UserDaoImpl.save(..))")
public void demo(){
System.out.println("权限校验");
}
//后置通知
// @AfterReturning(value = "execution(* com.dao.impl.UserDaoImpl.find(..))" ,returning = "result")
@AfterReturning(value = "MyAspectAnno.pointcut1()" , returning = "result")
public void demo2(Object result ){
System.out.println("保存日志");
System.out.println(result);
}
//环绕通知
@Around(value = "execution(* com.dao.impl.UserDaoImpl.update(..))")
public Object demo3(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("权限校验");
//运行原方法
Object o = joinPoint.proceed();
System.out.println("保存日志");
return o;
}
//异常通知
@AfterThrowing(value = "execution(* com.dao.impl.UserDaoImpl.delete(..))", throwing = "throwable")
public void demo4(Throwable throwable) {
System.out.println("异常通知======"+throwable.getMessage());
}
//最终通知
// @After(value = "execution(* com.dao.impl.UserDaoImpl.find(..))")
@After(value = "MyAspectAnno.pointcut1()")
public void demo5(){
System.out.println("最终都要执行");
}
//切入点注解
@Pointcut(value = "execution(* com.dao.impl.UserDaoImpl.find(..))")
private void pointcut1(){}
}
运行实例
通知类型
- 前置通知
//前置通知
@Before(value = "execution(* com.dao.impl.UserDaoImpl.save(..))")
public void demo(){
System.out.println("权限校验");
}
- 后置通知
//后置通知
// @AfterReturning(value = "execution(* com.dao.impl.UserDaoImpl.find(..))" ,returning = "result")
@AfterReturning(value = "MyAspectAnno.pointcut1()" , returning = "result")
public void demo2(Object result ){
System.out.println("保存日志");
System.out.println(result);
}
- 环绕通知
//环绕通知
@Around(value = "execution(* com.dao.impl.UserDaoImpl.update(..))")
public Object demo3(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("权限校验");
//运行原方法
Object o = joinPoint.proceed();
System.out.println("保存日志");
return o;
}
- 异常通知
//异常通知
@AfterThrowing(value = "execution(* com.dao.impl.UserDaoImpl.delete(..))", throwing = "throwable")
public void demo4(Throwable throwable) {
System.out.println("异常通知======"+throwable.getMessage());
}
- 最终通知
//最终通知
// @After(value = "execution(* com.dao.impl.UserDaoImpl.find(..))")
@After(value = "MyAspectAnno.pointcut1()")
public void demo5(){
System.out.println("最终都要执行");
}
- 切入点注解
当通知的某一个类型方法在多处都要增强,如果万一以后修改某个方法,那比较麻烦,所以出现了切入点的注解
//切入点注解
@Pointcut(value = "execution(* com.dao.impl.UserDaoImpl.find(..))")
private void pointcut1(){}
======================================================
//最终通知
// @After(value = "execution(* com.dao.impl.UserDaoImpl.find(..))")
@After(value = "MyAspectAnno.pointcut1()")
public void demo5(){
System.out.println("最终都要执行");
}
//后置通知
// @AfterReturning(value = "execution(* com.dao.impl.UserDaoImpl.find(..))" ,returning = "result")
@AfterReturning(value = "MyAspectAnno.pointcut1()" , returning = "result")
public void demo2(Object result ){
System.out.println("保存日志");
System.out.println(result);
}
spring的JDBC模板的使用
spring框架是一站式框架,提供了每一层的解决方案。
在持久层的决绝方案是:ORM模块和JDBC模板
spring JDBC模板的使用
- 要想使用JDBC模板,必须导入相关的jar包
连接数据库的jar包:mysql-connector-java-5.1.39-bin.jar
spring框架中JDBC模板的jar包:
spring-jdbc-4.2.4.RELEASE.jar
spring-tx-4.2.4.RELEASE.jar
- JDBC模板的使用,代码实现
注意:1. 使用的是spring框架自带的连接池,也可以使用第三方开源的连接池:c3p0等。
2. spring的JDBC模板是用来简化数据库的CRUD操作的,类似于DBUtils工具类。连接数据库还是得依赖于连接池。
@Test
public void demo(){
//使用spring自带的数据库连接池
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/hou");
dataSource.setUsername("root");
dataSource.setPassword("123456");
//创建spring的jdbc模板,类似于DbUtils,主要作用是简化了CRUD 的操作
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("insert into account values (null,?,?)","张三",1000d);
}
将数据库连接池和JDBC模板交给spring管理
将数据库连接池交给spring管理,其中要给属性赋值,有两种办法
- 直接赋值响应的加载器,url,数据库用户名,数据库密码
- 使用配置文件,将加载器,url 等写在配置文件中,在applicationContext.xml中加载配置文件。
<!--引入配置文件-->
<!--第一种方法:推荐-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--第二种方法:不推荐-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"></property>
</bean>
<!--将spring的数据库连接池交给spring管理-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/hou"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<!--使用配置文件jdbc.properties,推荐使用-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClass}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--将spring的JDBC模板交给spring管理-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class springDemo2 {
@Resource(name = "jdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Test
public void demo2(){
jdbcTemplate.update("insert into account values (null,?,?)","王五33",1000d);
}
}
使用c3p0开源连接池
- 引入相关jar包
进入spring框架中整理好了的相关的c3p0的jar包,不需要去下载官网的单纯的c3p0jar包
com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
- 将连接池交给spring管理
<!--使用c3p0开源连接池,并将其交给spring管理-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/hou"></property>
<property name="user" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<!--将spring的JDBC模板交给spring管理-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
使用dbcp开源连接池
- 引入相关jar包
进入spring框架中整理好了的相关的c3p0的jar包,不需要去下载官网的单纯的c3p0jar包
com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
- 将连接池交给spring管理
<!--使用dbcp开源连接池,并将其交给spring管理-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/hou"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<!--将spring的JDBC模板交给spring管理-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
使用spring的JDBC模板实现数据库的CRUD操作
- 增加操作
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class springDemo2 {
@Resource(name = "jdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Test
public void demo2(){
jdbcTemplate.update("insert into account values (null,?,?)","王五33",1000d);
}
}
- 删除操作
@Test
public void demo4(){
jdbcTemplate.update("delete from account where id = ?",1);
}
- 修改操作
@Test
public void demo3(){
jdbcTemplate.update("update account set name = ?,money = ? where id = ?","哈哈哈",2000d,2);
}
- 查询操作
将数据封装到对象中去
- 封装到一个对象中去
使用jdbcTemplate.queryForObject();返回一个对象- 封装到list集合中去
使用jdbcTemplate.query();返回List集合
注意:spring提供的JDBC模板需要自己封装对象,不与DbUtils一样,有自己的实现
> 类,这里只是提供一个接口,自己去实现。
@Test
//查询操作
public void demo5(){
//普通查询单个属性
String name = jdbcTemplate.queryForObject("select name from account where id = ?", String.class, 2);
System.out.println(name);
//统计查询
Long aLong = jdbcTemplate.queryForObject("select count(*) from account", Long.class);
System.out.println(aLong.intValue());
//将查询到的数据封装到对象中去,spring提供的JDBC模板必须要自己去封装数据
//封装到一个对象中去
Object o = jdbcTemplate.queryForObject("select * from account where id = ?", new RowMapper<Object>() {
@Override
/*
* resultSet:返回的是结果集,
* i:表示的是行号,遍历到第几行了,当返回的是多个对象的时候,这个方法相当于遍历,每一行都会执行一次这个方法
* */
public Object mapRow(ResultSet resultSet, int i) throws SQLException {
Account account = new Account();
account.setId(resultSet.getInt("id"));
account.setName(resultSet.getString("name"));
account.setMoney(resultSet.getDouble("money"));
return account;
}
}, 2);
System.out.println(o);
//将多个数据封装到集合中
List<Account> list = jdbcTemplate.query("select * from account", new RowMapper<Account>() {
@Override
//注意:查询多个数据,将其封装到多个对象中,并将对象封装到一个集合中
//实现数据的封装只是当前行的数据,它会遍历每一行,从而达到每一行的数据都在一个对象中
public Account mapRow(ResultSet resultSet, int i) throws SQLException {
Account account = new Account();
account.setId(resultSet.getInt("id"));
account.setName(resultSet.getString("name"));
account.setMoney(resultSet.getDouble("money"));
return account;
}
});
System.out.println(list.size());
}
spring的事务的管理
spring的事务管理的API
spring进行事物管理的时候,首先根据平台事物管理器根据事物的定义信息(事物的属性)进行事物的管理,事物管理的过程中产生的事物的状态,保存到事物状态对象中去。
- 平台事物管理器:PlatFormTransactionManager
平台事物管理器,其实是一个接口,是spring真正管理事物的对象,实现类有:
- DataSourceTransactionManager:底层使用的是JDBC模板管理事物的
- HibernateTransactionManager:底层使用的是Hibernate管理事物的
- 事物定义信息:TransactionDefinition
定义事物的信息:也就是事物的属性,有五个属性
传播行为、隔离级别、是否可读、回滚规则,事物超时
- 事物的状态:TransactionStatus
事务状态:用于记录在事务管理过程中,事务的状态的对象
spring事务的传播行为
Spring中提供了七种事务的传播行为:
保证多个操作在同一个事务中
PROPAGATION_REQUIRED :默认值,如果A中有事务,使用A中的事务,如果A没有,创建一个新的事务,将操作包含进来
PROPAGATION_SUPPORTS :支持事务,如果A中有事务,使用A中的事务。如果A没有事务,不使用事务。
PROPAGATION_MANDATORY :如果A中有事务,使用A中的事务。如果A没有事务,抛出异常。保证多个操作不在同一个事务中
PROPAGATION_REQUIRES_NEW :如果A中有事务,将A的事务挂起(暂停),创建新事务,只包含自身操作。如果A中没有事务,创建一个新事务,包含自身操作
PROPAGATION_NOT_SUPPORTED :如果A中有事务,将A的事务挂起。不使用事务管理。
PROPAGATION_NEVER :如果A中有事务,报异常。嵌套式事务
PROPAGATION_NESTED :嵌套事务,如果A中有事务,按照A的事务执行,执行完成后,设置一个保存点,执行B中的操作,如果没有异常,执行通过,如果有异常,可以选择回滚到最初始位置,也可以回滚到保存点。
spring事务的管理
银行转账的环境搭建
1.使用事物管理器,需要到入jar包
spring-tx-4.2.4.RELEASE.ja
- 创建service层和dao层
service层
package com.service;
public interface AccountService {
public void trans(String from,String to,double money);
public void trans3(String from,String to,double money);
}
=================================================================
@Transactional(propagation = Propagation.REQUIRED ,readOnly = false)
public class AccountServiceImpl implements AccountService {
@Resource(name = "accountDao")
private AccountDao accountDao;
public void trans(String from, String to, double money) {
accountDao.outMoney(from,money);
int a = 2/0;
accountDao.inMoney(to,money);
}
//如果这个方法不使用事物
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void trans2(String from, String to, double money) {
accountDao.outMoney(from,money);
int a = 2/0;
accountDao.inMoney(to,money);
}
@Resource(name = "transactionTemplate")
private TransactionTemplate transactionTemplate;
//使用自己编写代码的方式管理事物
public void trans3(String from, String to, double money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
accountDao.outMoney(from,money);
int a = 2/0;
accountDao.inMoney(to,money);
}
});
}
}
dao层
为什么dao层实现类继承JdbcDaoSupport类,因为为了简化xml的配置,
向这个dao层的实现类注入数据库连接池,就会自动给你创建JdbcTemplate对象,
所以就不用再配置文件中注入JdbcTemplate对象了。
public interface AccountDao {
//转出
public void outMoney(String from, double money);
//转入
public void inMoney(String to,double money);
public void aVoid();
}
====================================================
public class AccountDaoImp extends JdbcDaoSupport implements AccountDao {
@Override
public void outMoney(String from, double money) {
JdbcTemplate jdbcTemplate = this.getJdbcTemplate();
jdbcTemplate.update("update account set money = money - ? where name = ?",money,from);
}
@Override
public void inMoney(String to,double money) {
JdbcTemplate jdbcTemplate = this.getJdbcTemplate();
jdbcTemplate.update("update account set money = money + ? where name = ?",money,to);
}
public void aVoid(){
System.out.println("dadsadsa");
}
}
- 测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:tx3.xml")
public class SpringDemo3 {
@Resource(name = "accountService")
private AccountService accountService;
@Test
public void demo(){
accountService.trans("哈哈哈","王五",100d);
}
@Test
public void demo2(){
accountService.trans3("哈哈哈","王五",100d);
}
}
编程式的事务管理(自己写代码)
第一步:配置平台事务管理器
<!--<!–配置事物平台管理器–>-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
第二步:Spring提供了事务管理的模板类
配置事务的管理的模板类
<!--配置事物的管理模板,使得事物管理更加的简单-->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<!--注入事物平台管理器-->
<property name="transactionManager" ref="dataSourceTransactionManager"></property>
</bean>
第三步:在业务层注入事务管理的模板
使用注解方式注入,开启注解
<context:annotation-config></context:annotation-config>
@Resource(name = "transactionTemplate")
private TransactionTemplate transactionTemplate;
第四步:编写事务管理的代码,在service层
//使用自己编写代码的方式管理事物
public void trans3(String from, String to, double money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
accountDao.outMoney(from,money);
int a = 2/0;
accountDao.inMoney(to,money);
}
});
}
声明式的事务管理–实质是AOP
xml方式声明的事务管理
在事物定义的规则中的name属性,是其规则,规定类中的某个具体的方法采用这个事务规则,相当于切面类。
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:annotation-config></context:annotation-config>
<!--<!–引入配置文件–>-->
<!--<!–第一种方法:推荐–>-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--<!–使用c3p0开源连接池,并将其交给spring管理–>-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/hou"></property>
<property name="user" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<bean id="accountService" class="com.service.impl.AccountServiceImpl">
</bean>
<bean id="accountDao" class="com.dao.impl.AccountDaoImp">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--<!–配置事物平台管理器–>-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事物的增强,相当于aop的切面类>-->
<tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
<!--事物管理的规则-->
<tx:attributes>
<!--name属性其实是规则,要与aop中的expression属性区分,name属性其实是规定要使用该规则的类中具体哪个方法
expression属性定位到目标类
-->
<tx:method name="*" read-only="false" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--<!–AOP的配置–>-->
<aop:config>
<aop:pointcut id="pointcut1" expression="execution(* com.service.impl.AccountServiceImpl.trans(..))"></aop:pointcut>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"></aop:advisor>
</aop:config>
</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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:annotation-config></context:annotation-config>
<!--<!–引入配置文件–>-->
<!--<!–第一种方法:推荐–>-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--<!–使用c3p0开源连接池,并将其交给spring管理–>-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/hou"></property>
<property name="user" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<bean id="accountService" class="com.service.impl.AccountServiceImpl">
</bean>
<bean id="accountDao" class="com.dao.impl.AccountDaoImp">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--<!–配置事物平台管理器–>-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--使用注解的方式,开启注解事物-->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"></tx:annotation-driven>
</beans>
具体实现过程
目标类中要使用注解
如果想某个方法不使用事物
@Transactional(propagation = Propagation.REQUIRED ,readOnly = false)
public class AccountServiceImpl implements AccountService {
@Resource(name = "accountDao")
private AccountDao accountDao;
public void trans(String from, String to, double money) {
accountDao.outMoney(from,money);
int a = 2/0;
accountDao.inMoney(to,money);
}
//如果这个方法不使用事物
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void trans2(String from, String to, double money) {
accountDao.outMoney(from,money);
int a = 2/0;
accountDao.inMoney(to,money);
}
}