spring5整理:(七)AOP

把一个个的横切关注点放到某个模块中去,称之为切面。那每一个的切面都能影响业务的某一种功能,切面的目的就是功能增强,如日志切面就是一个横切关注点,应用中许多方法需要做日志记录的只需要插入日志的切面即可。

AOP术语:

1.Joinpoint连接点,被拦截到需要被增强的方法。where:去哪里做增强

2.Pointcut:切入点,哪些包中的哪些类中的哪些方法,可以认为是连接点的集事。where:去哪些地方做增强

3.Advice:增强,当拦截到Joinpoint之后,在方法执行的时机(when)做什么样(what)的增强,根据时机分为:前置增强,后置增强,异常增强,最络增强,环绕增强

4.Aspect:切面,Pointcut+Advice,去哪些地方+在什么时机+做什么增强

5.Target:目标对象,被代理的目标对象

6.Wearing:织入,把Advice加到Target上之后,创建出Proxy对象的过程

7.Proxy:一个类被AOP织入增强后,产生的代理类

Advice(增强)执行时机:

 

Pointcut语法:

execution(modifiers-pattern? ret0type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

中文:

execution(<修饰符>? <返回类型> <声明类型>? <方法名>(<参数>) <异常>?)

切入点表达式中的通配符:

   *:匹配任何部分,但是只能表示一个单词

   ..:可用于全限定名中和方法参数中,分别表示子包和0到N个参数

常见的写法:

execution(* com.bigfong.test.service.*.*(..))
execution(* com.bigfong.test.service.*Service.*(..))
execution(* com.bigfong..service.*Service.*(..))

 

AOP配置三步:  what-where-when

使用JDK动态代理开发AOP:

1.domain类;Employee

2.dao接口

public interface IEmployeeDAO {
    void save(Employee emp);
    void update(Employee emp);
}

   dao实现类

public class EmployeeDAOImpl implements IEmployeeDAO {

    @Override
    public void save(Employee emp) {
        System.out.println("保存数据");
        
    }

    @Override
    public void update(Employee emp) {
        System.out.println("修改数据");
    }

}

3.service接口

public interface IEmployeeService {
    void save(Employee emp);
    void update(Employee emp);
}

   service接口实现类

public class EmployeeServiceImpl implements IEmployeeService {

    private IEmployeeDAO dao;
    
    public void setDao(IEmployeeDAO dao) {
        this.dao = dao;
    }
    @Override
    public void save(Employee emp) {
        dao.save(emp);
        System.out.println("保存成功");
    }

    @Override
    public void update(Employee emp) {
        dao.update(emp);
        throw new RuntimeException("出错啦");
    }

}

四.模拟事务管理器

public class TransactionManager {

    public void begin() {
        System.out.println("开启事务");
    }
    
    public void commit() {
        System.out.println("提交事务");
    }
    
    public void rollback() {
        System.out.println("回滚事务");
    }
}

五.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:context="http://www.springframework.org/schema/context"
    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/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">

    <bean id="employeeDAO" class="com.bigfong.aopxml.dao.impl.EmployeeDAOImpl"/>
	
	

	<bean  class="com.bigfong.aopxml.service.impl.EmployeeServiceImpl">
		<property name="dao" ref="employeeDAO"/>
	</bean>
	
	<!-- AOP配置:在什么地点+什么时机+做什么 -->
	<!-- 1.WHAT,做什么增强 -->
	<bean id="txManager" class="com.bigfong.aopxml.tx.TransactionManager"/>
	<aop:config>
		<!-- 配置AOP切面 -->
		<aop:aspect ref="txManager"> <!-- 关联WHAT -->
			<!-- 2.WHERE,在哪些包中的哪些类中的哪些方法上做增强 -->
			<aop:pointcut id="txPoint" expression="execution(* com.bigfong.aopxml.service.*Service.*(..))" />
			<!-- 3.WHEN,在方法执行的什么时机做增强 -->
			<aop:before method="begin" pointcut-ref="txPoint"/>
			<aop:after-returning method="commit" pointcut-ref="txPoint"/>
			<aop:after-throwing method="rollback" pointcut-ref="txPoint"/>
		</aop:aspect>
	</aop:config>
	
	
</beans>

6.测试代码

@SpringJUnitConfig
public class App {
    @Autowired
    private IEmployeeService service;
    
    @Test
    public void testSave()throws Exception {
        System.out.println(service.getClass());
        service.save(new Employee());
    }
    
    @Test
    public void testUpdate()throws Exception {
        System.out.println(service.getClass());
        service.update(new Employee());
    }
}

 

 

使用CGLIB动态代理实现事务:

与使用JDK动态代理开发AOP类似,需要修改xml中<aop:config proxy-target-class="true">

 

各种时机的增强

1.aop:before(前置增强):在方法执行之前增强(应用:权限控制,日志等)

2.aop:after-returning(后置增强):在方法正常执行完成之后(在retrun返回值前)执行增强(中间没有遇到任何异常)(应用:提交事务、统计分析数据结果等)

3.aop:throwing(异常增强):在方法抛出异常退出时执行增强  (应用:回滚事务、记录日志的异常信息等)

4.aop:after(最终增强):在方法执行之后执行,相当于在finally里面执行skin以通过配置throwing来获得拦截到的异常信息 (应用:释放资源等)

5.aop:around(环绕增强):可以在方法调用前/后完成自定义的行业,有两个要求:

                                           1)方法需要返回一个Object(返回结果)

                                            2)方法的第一个参数必须是ProceedingJoinPoint(可以继续向下传递的连接点)

                                         (应用:缓存、性能日志、权限、事务管理等)

 

增强丰富参数配置

1.在增强方法中获取异常信息

xml配置:

    <aop:after-throwing method="roallback" pointcut-ref="txPoint"  throwing="ex">

java代码:

   public void rollback(){

     System.out.println("回滚事务" + ex);

   }

2.获取被增强方法信息,并传递给增强方法

Spring AOP提供org.aspectj.lang.JoinPoint类,作为增强方法的第一个参数。

JoinPoint:提供访问当前被增强方法的真实对象、代理对象、方法参数等数据

ProceedingJoinPoint:JoinPoint子类,只用于环绕增强中,可以处理被增强方法

使用JoinPoint方法

public void begin(JoinPoint jp){
    代理对象:jp.getThis().getClass();
    目标对像:jp.getTarget().getClass();
    被增强方法参数:Arrays.toString(jp.getArgs());
    当前连接点签名:jp.getSignature();
    当前连接点类型:jp.getKind();
}

使用ProceedingJoinPoint类

public Object around(ProceedingJoinPoint pjp){
    Object ret = null;
    //开启事务
    try{
        //执行目标方法
        ret = pjp.proceed();
        //提交事务
    }catch(Throwable ex){
        //回滚事务
    }finally{
        //释放资源
    }
    return ret;
}

 

 

 

注解配置事务--默认使用JDK动态代理

1.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:context="http://www.springframework.org/schema/context"
    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/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">

	<!-- DI注解解析器 -->
	<context:annotation-config/>
	<!-- Ioc注解解析器 -->
	<context:component-scan base-package="com.bigfong.aopanno"/>
	<!-- AOP注解解析器 -->
	<aop:aspectj-autoproxy/>

	
</beans>

2.实体类Employee

3.IEmployeeDAO接口类,EmployeeDAOImpl是对IEmployeeDAO的实现类,接口实现类需添加注解@Repository

public interface IEmployeeDAO {
    void save(Employee emp);
    void update(Employee emp);
}

@Repository
public class EmployeeDAOImpl implements IEmployeeDAO {

    @Override
    public void save(Employee emp) {
        System.out.println("保存员工");
        
    }

    @Override
    public void update(Employee emp) {
        System.out.println("修改员工");
    }

}

4.IEmployeeService接口类,EmployeeServiceImpl是对IEmployeeService的实现类,并添加注解@Service

public interface IEmployeeService {
    void save(Employee emp);
    void update(Employee emp);
}

@Service
public class EmployeeServiceImpl implements IEmployeeService {
    
    @Autowired
    private IEmployeeDAO dao;
    

    @Override
    public void save(Employee emp) {
        dao.save(emp);
        System.out.println("保存成功");
    }

    @Override
    public void update(Employee emp) {
        dao.update(emp);
        throw new RuntimeException("程序出错啦");
    }

}

5.模拟事务管理器

@Component
@Aspect //配置切面

public class TransactionManager {
    //XML:<aop:pointcut id="txPoint" expression="execution(* com.bigfong.aopanno.service.*Service.*(..))" />
    @Pointcut("execution(* com.bigfong.aopanno.service.*Service.*(..))")
    public void txPoint() {
        
    }
    
    @Before("txPoint()")  //相当于调用上面的方法
    public void begin() {
        System.out.println("开启事务");
    }
    
    @AfterReturning("txPoint()")
    public void commit() {
        System.out.println("提交事务");
    }
    
    @AfterThrowing(value="txPoint()",throwing="ex")
    public void rollback(JoinPoint jp,Throwable ex) {
        System.out.println("回滚事务,异常信息:"+ex.getMessage());
    }
    
    @After("txPoint()")
    public void close() {
        System.out.println("释放资源");
    }
    
    @Around("txPoint()")
    public Object aroundMethod(ProceedingJoinPoint pjp) {
        Object ret = null;
        System.out.println("环绕增强:开启事务");
        try {
            ret = pjp.proceed();//调用真实对象的方法
            System.out.println("环绕增强:正常执行真实方法");
        }catch (Throwable e) {
            System.out.println("环绕增强:回滚事务,异常信息:"+e.getMessage());
        }finally {
            System.out.println("环绕增强:释放资源");
        }
        return ret;
    }
}

 

6.测试代码

@Autowired
private IEmployeeService service;

@Test
public void testSave()throws Exception {
    System.out.println(service.getClass());
    service.save(new Employee());
}

@Test
public void testUpdate()throws Exception {
    System.out.println(service.getClass());
    service.update(new Employee());
}

 

注解配置事务--使用CGLIB动态代理

1.xml配置:

<aop:aspectj-autoproxy proxy-target-class="true"/>

2.修改切入点静态式

@Pointcut("execution(* com.bigfong.aopanno.service..*(..))")
public void txPoint() {
        
}

 

上一篇:spring5整理:(六)CGLIB动态代理-模拟事务

下一篇:spring5整理:(八)DAO 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值