一、 springAOP
1、作用: 使得事务、日志、安全性框架、权限、目标方法之间完全是松耦合的
2、组成
1、切面: 事务、日志、安全性框架、权限等都是切面
2、通知: 切面中的方法就是通知
3、目标类
4、切入点 只有符合切入点,才能让通知和目标方法结合在一起
5、织入: 形成代理对象的方法的过程
注:代理对象的方法就是通知和目标方法的结合体
3、相对于动态代理,省略了写拦截器的过程
4、切入点表达式详解
5、springAOP的具体加载步骤:
1、当spring容器启动的时候,加载了spring的配置文件
2、为配置文件中所有的bean创建对象
3、spring容器会解析aop:config的配置
解析切入点表达式,用切入点表达式和纳入spring容器中的bean做匹配
如果匹配成功,则会为该bean创建代理对象,代理对象的方法=目标方法+通知
如果匹配不成功,不会创建代理对象
4、在客户端利用context.getBean获取对象时,如果该对象有代理对象则返回代理对象,
如果无代理对象,则返回目标对象
5、如果目标类没有实现接口,则spring容器会采用cglib的方式产生代理对象,
如果实现了接口,会采用jdk的方式
6、各种通知详解
1、前置通知
1、在目标方法执行之前执行
2、无论目标方法是否抛出异常,都执行,因为在执行前置通知的时候,目标方法还没有执行,还没有遇到异常
例:
------------------------------------------------------------------------------
// 前置通知
public void beginTransaction(){
System.out.println("before inform");
this.transaction = sessionFactory.getCurrentSession().beginTransaction();
}
------------------------------------------------------------------------------
2、后置通知
1、在目标方法执行之后执行
2、当目标方法遇到异常,后置通知将不再执行
3、后置通知可以接受目标方法的返回值,但是必须注意:
后置通知的参数的类型为Object,且名称和配置文件中returning="var"的值是一致的
例:
------------------------------------------------------------------------------
不带参数的
// 后置通知
public void commit(){
System.out.println("after return inform");
this.transaction.commit();
}
// 不带返回值的目标方法
public void savePerson(Person person) {
sessionFactory.getCurrentSession().save(person);
}
带参数的
public void commit(Object var){
System.out.println("after return inform");
System.out.println(var);
this.transaction.commit();
}
// 带返回值的目标方法
public String savePerson(Person person) {
//int i = 1/0;
System.out.println("目标方法");
return "返回值";
}
------------------------------------------------------------------------------
3、最终通知:
1、在目标方法执行之后执行
2、无论目标方法是否抛出异常,都执行,因为相当于finally
例:
------------------------------------------------------------------------------
public void fianllyMethod(){
System.out.println("finally inform");
}
------------------------------------------------------------------------------
4、异常通知
1、接受目标方法抛出的异常信息
2、步骤
在异常通知方法中有一个参数Throwable ex
在配置文件中
注: throwing也要和切面中的异常通知的类型为Throable的参数名称保持一致
例:
-------------------------------------------------------------------------------
public void throwingMethod(Throwable ex){
System.out.println(ex.getMessage());
}
// 目标类
public void savePerson(Person person) {
int i = 1/0;
sessionFactory.getCurrentSession().save(person);
}
-------------------------------------------------------------------------------
5、环绕通知
1、环绕通知可以控制目标方法的执行
方式: 在环绕通知中加一个参数:
org.aspectj.lang.JoinPoint包中的ProceedingJoinPoint joinPoint
然后在环绕通知中显示调用ProceedingJoinPoint的proceed()方法,,则执行目标方法
2、同时,各种通知若加JoinPoint参数(org.aspectj.lang.JoinPoint包),还可以获取目标方法的信息
例:
-------------------------------------------------------------------------------
不调用目标方法:
public void aroundMethod(){
System.out.println("around inform");
}
// 目标方法 注: 此时未调用目标方法
public String savePerson(Person person) {
System.out.println("目标方法");
return "返回值";
}
调用目标方法:
public void aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable{
joinPoint.proceed();
// 显示的调用目标方法的执行,可以控制目标方法是否执行
System.out.println("around inform with targetMethod");
System.out.println("目标方法的方法名:"+joinPoint.getSignature().getName());
}
// 目标方法: 注: 此时调用了目标方法
public String savePerson(Person person) {
System.out.println("目标方法");
return "返回值";
}
-------------------------------------------------------------------------------
7、例1: 一个切面
--------------------------------------------------------------------------------
public class Person implements Serializable {
private Long pid;
private String pname;
private String psex;
}
// 接口
public interface PersonDao {
public void savePerson(Person person);
}
// 目标类
public class PersonDaoImpl extends HibernateUtil implements PersonDao {
@Override
public void savePerson(Person person) {
sessionFactory.getCurrentSession().save(person);
}
}
// 切面
public class MyTransaction extends HibernateUtil{
private Transaction transaction;
// 通知
public void beginTransaction(){
this.transaction = sessionFactory.getCurrentSession().beginTransaction();
}
// 通知
public void commit(){
this.transaction.commit();
}
}
配置文件:
测试:
public class PersonTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext(
"cn/itcast/spring/aop/applicationContext.xml");
// 注: 此处得到的是代理对象
PersonDao personDao = (PersonDao) context.getBean("personDao");
Person person = new Person();
person.setPname("aaa");
person.setPsex("男");
personDao.savePerson(person);
}
}
--------------------------------------------------------------------------------
例1: 多个切面
--------------------------------------------------------------------------------
目标类:
public class SalaryManagerImpl {
public void show(){
System.out.println("目标方法:查看工资");
}
}
切面1:
public class Logger {
public void logger(){
System.out.println("logger");
}
}
切面2:
public class Security {
public void security(){
System.out.println("security");
}
}
切面3:
public class Privilege {
private String access;
// set/get属性
public void hasAccess(ProceedingJoinPoint joinPoint) throws Throwable{
if(this.access.equals("admin")){
joinPoint.proceed();
}else{
System.out.println("对不起,您没有权限");
}
}
}
配置文件:
测试:
public class SalaryTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("
cn/itcast/spring/aop/aspeces/applicationContext.xml");
SalaryManagerImpl proxy = (SalaryManagerImpl) context.getBean("salaryManager");
proxy.show();
}
}
--------------------------------------------------------------------------------
8、例:统一的错误异常处理
--------------------------------------------------------------------------------
public class PersonAction {
private PersonService personService = new PersonServiceImpl();
// set/get属性
public String savePerson() throws Exception{
this.personService.savePerson();
return null;
}
}
public interface PersonService {
public void savePerson() throws Exception;
}
public class PersonServiceImpl implements PersonService {
PersonDao personDao = new PersonDaoImpl();
// set/get属性
@Override
public void savePerson() throws Exception {
this.personDao.savePerson();
throw new RuntimeException("service层异常");
}
}
public interface PersonDao {
public void savePerson() throws Exception;
}
public class PersonDaoImpl implements PersonDao {
@Override
public void savePerson() throws Exception{
System.out.println("save person daoImpl");
throw new RuntimeException("dao层异常");
}
}
public class MyException {
public void myException(Throwable ex){
System.out.println(ex.getMessage());
}
}
配置文件:
测试:
public class UnionExceptionTest {
@Test
public void test() throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("
applicationContext.xml");
PersonAction personAction = (PersonAction) context.getBean("personAction");
personAction.savePerson();
}
}
--------------------------------------------------------------------------------
9、 springAOP注解的形式
--------------------------------------------------------------------------------
public class Person implements Serializable {
private Long pid;
private String pname;
private String psex;
// set/get属性
}
public interface PersonDao {
public void savePerson(Person person);
}
@Repository("personDao")
public class PersonDaoImpl extends HibernateUtil implements PersonDao {
@Override
public void savePerson(Person person) {
sessionFactory.getCurrentSession().save(person);
}
}
/**
@Aspect相当于:
*/
// 切面
@Component("myTransaction")
@Aspect
public class MyTransaction extends HibernateUtil{
private Transaction transaction;
/**
@Pointcut("execution(* cn.itcast.spring.aop.annotation.PersonDaoImpl.*(..))")相当于
*/
@Pointcut("execution(* cn.itcast.spring.aop.annotation.PersonDaoImpl.*(..))")
private void perform(){} // 方法签名,返回值必须是void,并且方法的修饰符最好是private
// 前置通知
/**
@Before("perform()")相当于:
*/
@Before("perform()")
public void beginTransaction(){
this.transaction = sessionFactory.getCurrentSession().beginTransaction();
}
// 后置通知
/**
@AfterReturning(value="perform()",returning="var")相当于:
*/
@AfterReturning(value="perform()",returning="var")
public void commit(Object var){
this.transaction.commit();
}
}
配置文件:
测试:
public class PersonTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("
cn/itcast/spring/aop/annotation/applicationContext.xml");
PersonDao personDao = (PersonDao) context.getBean("personDao");
Person person = new Person();
person.setPname("bbb");
person.setPsex("男");
personDao.savePerson(person);
}
}
--------------------------------------------------------------------------------