博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring中IOP的配置
阅读量:3906 次
发布时间:2019-05-23

本文共 11064 字,大约阅读时间需要 36 分钟。

1 案例

需求: 完成转账业务, 事务的支持:

1.1开发数据库表:Account id name money、

开发实体类: Account
public class Account {
private Integer id;
private String name;
private double money;
}
1.2开发AccountDao ; 查询, 更新方法:
package com.yidongxueyuan.spring.dao;

import com.yidongxueyuan.spring.pojo.Account;

public interface AccountDao {

/**
* 查询用户:
* @param accountName
* @return
*/
Account findAccountByName(String accountName);

/** * 更新操作:  * @param newAccount */void updateAccount(Account newAccount);

}

1.3开发AccountDaoImpl ; DBUtils链接数据库。
package com.yidongxueyuan.spring.dao.impl;

import java.sql.SQLException;

import org.apache.commons.dbutils.QueryRunner;

import org.apache.commons.dbutils.handlers.BeanHandler;

import com.yidongxueyuan.spring.dao.AccountDao;

import com.yidongxueyuan.spring.pojo.Account;
import com.yidongxueyuan.spring.utils.TransactionManager;

public class AccountDaoImpl implements AccountDao {

//获得对象, 不需要给出数据源: 	private QueryRunner qr= new QueryRunner();	@Override	public Account findAccountByName(String accountName) {				try {			String sql ="select * from account where name =?";			Account account = qr.query(TransactionManager.getConnection(), sql, new BeanHandler
(Account.class),accountName); return account; } catch (SQLException e) { e.printStackTrace(); } return null; } @Override public void updateAccount(Account newAccount) { try { String sql ="update account set money = ? where name =?"; qr.update(TransactionManager.getConnection(), sql, newAccount.getMoney(),newAccount.getName()); } catch (SQLException e) { e.printStackTrace(); } }

}

1.4开发AccountService ; 定义业务方法: transfer
package com.yidongxueyuan.spring.service;

public interface AccountService {

/**
* 业务方法, 实现转账
* @param sourceAccount 来源账户
* @param targetAccount 目标账户
* @param money 转账金额
*/
public void transfer(String sourceAccount,String targetAccount,float money);
}

1.5开发AccountServiceImpl实现类:

package com.yidongxueyuan.spring.service.impl;

import com.yidongxueyuan.spring.dao.AccountDao;

import com.yidongxueyuan.spring.dao.impl.AccountDaoImpl;
import com.yidongxueyuan.spring.pojo.Account;
import com.yidongxueyuan.spring.service.AccountService;

public class AccountServiceImpl implements AccountService{

private AccountDao dao= new AccountDaoImpl();
@Override
public void transfer(String sourceAccount, String targetAccout, float money) {

//开启事务: 				//根据来源账户: 		Account sourceAcc = dao.findAccountByName(sourceAccount);//aaa		//查询目标账户: 		Account targetAcc = dao.findAccountByName(targetAccout);// ccc		//来源账户减钱		sourceAcc.setMoney(sourceAcc.getMoney()-money); 		//目标账户增钱:		targetAcc.setMoney(targetAcc.getMoney()+money);		       //调用dao层的方法: 将变化后的数据保存哎数据库当中: 		dao.updateAccount(sourceAcc);				//模拟异常的发生: 		int i=1/0;		dao.updateAccount(targetAcc);			}

}

1.6工具类: 获得数据源的工具类

package com.yidongxueyuan.spring.utils;

import java.sql.Connection;

import java.sql.SQLException;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3P0Util {

/**
* 初始化一个对象:
* ComboPooledDataSource 是DataSource类的子类对象:
*/
private static DataSource ds = new ComboPooledDataSource();

/** * 返回一个数据源:  * @return */public static DataSource getDataSource(){	return ds; }/** * 获得一个链接对象:  * @return Connection链接对象:  */public static Connection getConnection(){	 try {		return ds.getConnection();	} catch (SQLException e) {		e.printStackTrace();	}	 return null; }

}

1.7工具类依赖的配置文件

<?xml version="1.0" encoding="UTF-8"?> com.mysql.jdbc.Driver jdbc:mysql:///customer root root 10 30 100 10 200

1.8测试

public class TestAccountService {
@Test
public void test1() {
//直接获得被代理对象:
AccountService service = new AccountServiceImpl();
service.transfer(“aaa”, “ccc”, 100);
}

}

测试总结: 在没有加入事务的前提下, 转账的过程当中: aaa 用户-100 但是ccc用户钱并没有增加: 不符合实际情况。 所以加入事务的支持。 保证转账的一个逻辑单元要么都成功, 要么都失败。

1.9 使用aop的方式事务

获得UserServiceImpl类的代理类对象; 在执行业务方法的时候, 在动态的加入事务的支持。

package com.yidongxueyuan.spring.utils;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.yidongxueyuan.spring.service.AccountService;

import com.yidongxueyuan.spring.service.impl.AccountServiceImpl;

/**

  • 定义一个工厂: 获得对象的代理对象:
  • @author Mrzhang

*/

public class BeanFactory {

/** * 定义了一个方法: 能够获得业务对象的代理对象:  * @return */public static AccountService getProxy(){		//被代理的对象: 	final AccountService service = new AccountServiceImpl();//只专注于转账:		//获得代理类: 	AccountService proxy= (AccountService)Proxy.newProxyInstance(			//代理类的类加载器			service.getClass().getClassLoader(), 			//代理类的接口当中所有的方法: 			service.getClass().getInterfaces(),			//InvocationHandler 接口: 定义代理类和被代理类的具体的代理策略: 			 new InvocationHandler() {								//proxy:代理类引用: 				// method:当前执行的方法: 				// args:执行方法的参数				//Object 调用方法的返回值: : 				@Override				public Object invoke(Object proxy, Method method, Object[] args)						throws Throwable {					Object obj =null; 										try {						//事务开启: 						TransactionManager.startTransaction();						//调用业务方法: 						obj = method.invoke(service, args);						//事务的提交: 						TransactionManager.commit();											} catch (Exception e) {						TransactionManager.rollback();						e.printStackTrace();					} finally{						//释放资源:					    					}					return obj;				}			});		return proxy;}

}

1.10测试:
@Test
public void test1() {
//直接获得被代理对象:
AccountService service = new AccountServiceImpl();
//获得service类的代理类对象:
AccountService proxy = BeanFactory.getProxy();
proxy.transfer(“aaa”, “ccc”, 100);
}

2AOP

2.1 aop概述
Aop 面向切面编程,底层是动态代理实现的。 是oop的延伸。 解决了oop开发过程当中遇到的一些问题。
Aop可以解决: 事务管理 日志的记录 权限的校验 性能的监控。

2.2 代理模式

代理模式: 分类静态代理&动态代理:
静态代理:
动态代理:分类:
基于接口的动态代理: JDK
基于普通Bean的代理: CGLIB (第三方,使用时候导入jar)

2.3 spring当中AOP

Aop 面向切面编程的思想, 这思想并不是spring提出的。 spring当中引用了aop。

Spring框架: aop的实现:

(1)spring当中对aop进行了具体的实现: (废弃)
(2)Spring引用了 AspectJ 对aop进行了很好的实现。(广泛使用)

2.4 aop相关的数据

public interface UserDao {		public User findUserById(int id);		public void saveUser(User user);		public void deleteUser(int id); 		public void updateUser(User user) ;	}

连接点(join point ): 可以被拦截到的点就是连接点。

增删改查这些方法都有机会可以被进行功能性的增强, 这些方法都是连接点。

切入点(PonitCut): 真正被拦截到的点。

真正被增强的方法, 就称之为切入点。 在实际开发过程当中, saveUser方法被增强了, 此时saveUser这个方法就是切入点

通知(advice) :增强(方法层面的增强)

在执行saveUser方法之前, 要执行checkPri这个方法,此时checkPri这个方法就称之为通知, 也叫作增强。

引介: (Introduction) : 类层面的增强。

目标:(Target) : 被增强的对象:

在开发当中, UserDao 需要被增强, UserDao就是增强的对象。

织入:(Weaving) :将通知(advice)应用到目标(target)的过程

saveUser方法需要在执行之前加入checkPri()进行权限的校验,这个过程就是织入。

代理对象(Proxy): 目标被增强后,就是一个代理对象。

切面: (aspect): 多个通知和多个切入点的集合。 多个通知的集合。

2.5 aop的入门案例

在这里插入图片描述
2.5.1 引入aop相关的jar包:
IOC: 4个核心+ 2个日志:
注解式开发: spring3.x 不需要导入其他的》
Spring4.x 引来了aop
Aop的开发: 4个:

在这里插入图片描述

第一个jar: aop联盟
第二个jar: aspectweaving
第三个jar: aop
第四个jar: spring 整合aspect

Spring当中自己提供了一个套实现: 开发只需要两个: aop , aopalliance

Spring引入了aspect后: aspectJ spring-aspect :

2.5.2 核心配置文件当中引入相关的约束:

2.5.3 定义接口 UserDao

public interface UserDao {

public User findUserById(int id);public void saveUser(User user);public void deleteUser(int id); public void updateUser(User user) ;

}

2.5.4 定义接口的实现:

UserDaoImplpackage com.yidongxueyuan.spring.dao.impl;import org.springframework.stereotype.Repository;import com.yidongxueyuan.spring.dao.UserDao;import com.yidongxueyuan.spring.pojo.User;public class UserDaoImpl implements UserDao {	@Override	public User findUserById(int id) {		System.out.println("根据id 进行用户的查询:");		return null;	}	@Override	public void saveUser(User user) {		System.out.println("save...");	}	@Override	public void deleteUser(int id) {		System.out.println("delete...");	}	@Override	public void updateUser(User user) {		System.out.println("update...");	}}

2.5.5 定义切面类 并且常见对象: (增强的集合)

package com.yidongxueyuan.spring.pojo;

/**

  • 定义一个切面: (通知的集合)
  • @author Mrzhang

*/

public class MyAspectXml {

/** *  定义了一个通知: (增强) */public void checkPri() {	System.out.println("权限的校验");}

}

2.5.6 通过配置的方法, 实现对UserDaoImpl当中的方法进行功能的增强。

ApplicationContext.xml当中进行配置L:

·

总结配置: 将切面类当中的增强应用在目标类的切点上。

2.5.7测试 (spring整合Junit后)

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class TestUserDao {		//整合后的单元测试: 	@Resource(name="userDao")	private UserDao userDao;		@Test	public void test2() throws Exception {				userDao.saveUser(new User());	}	}

2.6 spring整合junit

(1)加入单元测试的包:
在这里插入图片描述
(2)使用JUnit:

package com.yidongxueyuan.spring.test;import javax.annotation.Resource;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import com.yidongxueyuan.spring.dao.UserDao;import com.yidongxueyuan.spring.pojo.User;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class TestUserDao {		//整合后的单元测试: 	@Resource(name="userDao")	private UserDao userDao;		@Test	public void test2() throws Exception {		userDao.saveUser(new User());	}		//传统的单元测试: 	@Test	public void test1() throws Exception {		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");		UserDao dao = (UserDao)context.getBean("userDao");		dao.saveUser(new User());	}		}

2.7 spring当中提供的通知的类型:

五种通知类型:
2.7.1前置通知:

2.7.2 后置增强:

总结: 当异常通知执行了, 后置通知就不再执行了。

2.7.3 最终通知

2.7.4 异常抛出通知

总结: 如果最后通知执行, 异常抛出通知不执行。

异常抛出通知, 能够获得异常信息:

public void afterThrow(Throwable e) {// e的名称必须和配置文件当中抛出的名称一致。	System.out.println("异常抛出通知:  "+e.getMessage());//获得抛出的异常信息。}

总结: 前置, 后置, 最终, 异常抛出通知, 以上四个通知不可能通知执行。 后置通知和异常抛出通知只能执行一个。

当没有遇到异常的时候, 执行后置通知。
遇到了异常信息, 执行异常抛出通知。

2.7.5 环绕通知

切面当中增强的定义:

/**	 * 测试了代码: 环绕通知执行了, 但是业务代码没有执行: 	 * 	 * spring当中提供了一个对象: ProceedingJoinPoint 放行业务代码:  方法有返回值: 	 */	public Object around(ProceedingJoinPoint joinPoint) {				//放行业务代码: 		Object obj= null; 		try {			System.out.println("前置通知。");			obj= joinPoint.proceed();			System.out.println("后置通知。");		} catch (Throwable e) {			System.out.println("异常抛出通知: ");			e.printStackTrace();		} finally {			System.out.println("最终通知");		}		return obj; 			}核心配置文件当中配置环绕通知:           
测试。。。 总结: 环绕通知可以模拟前置,后置, 异常, 最终通知。 2.8 通用化切点的配置

2.9 execution 表达式的书写

Expression: 基于execution的书写:

语法:

访问权限修饰符 返回值 包名.类名.方法的名称(方法参数的类型)

访问权限可以省略的:

void com.yidongxueyuan.spring.dao.impl.UserDaoImpl.saveUser(…))

返回值: 可以写成具体的返回值类型: void

返回值类型可以使用通配符: * :带表任何的返回值。

包: 可以使用统配符: * 每一个就代表一级包。

execution( * .....UserDaoImpl.saveUser(…))"
*… 代表当前当前包,
expression=“execution( * *…UserDaoImpl.saveUser(…))”
类: 可以使用统配: * 代表所有的类。
方法: 可以同时通配符: * 代表任意的方法。
方法的参数:
如果写具体的类型: 基本数据类型: int double
如果是引用类型: 必须写全限定类型: java.lang.String.class Java.lang.Integer.class
方法的参数可以使用通配符:
*:带表有参数:
() 匹配不带参数;
(…) 匹配带参数的和不带参数的。

总结: 在实际开发当中, 不需要写统配方法:

统配的写法:
expression=“execution( * .*(…))”

建议:

  • com.yidongxueyuan.xx.impl..(…)
    业务包下的所有的实现类。

转载地址:http://bzqen.baihongyu.com/

你可能感兴趣的文章
编译cscope-15.8a遇到的问题与解决方案
查看>>
ubuntu下海信Hisense E920 usb连接不上的处理与adb的连接
查看>>
findbugs的ant脚本实践
查看>>
Ubuntu 12.04 安装 Subversion 1.7
查看>>
scp port 22: Connection refused
查看>>
ubuntu12.04命令行下安装RabbitVCS
查看>>
自定义cscope-index
查看>>
(ubuntu)在andorid andk工程中使用ccache加速编译速度
查看>>
android graphics system学习资料汇总
查看>>
GDB
查看>>
Oracle RAC Failover 详解
查看>>
[转载]Oracle RAC客户端连接不稳定的解决方法
查看>>
ORA RAC ORA-12545:因目标主机或对象不存在,连接失败!
查看>>
证明两节点能正常failover的sql
查看>>
oracle10g rac 报ora-12545错误的解决方案 转载
查看>>
Linux配置Xmanager
查看>>
IP地址正则表达式
查看>>
对SOAP消息头的处理
查看>>
webservice TCP Monitor
查看>>
Oracle中sysdate的时区偏差
查看>>