使用Spring实现AOP
1.通过编程形式基于XML实现AOP(JDK动态代理)
引入aspectjwarver环境
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.9.1</version>
</dependency>
修改核心配置文件
<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>
增强通知类,两个通知
package com.csi.proxy;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import java.util.Arrays;
public class TransactionManagerAdvice {
public TransactionManagerAdvice(){
System.out.println("开启数据库连接");
}
public void beforeT(JoinPoint joinPoint){
// System.out.println("被增强的类"+joinPoint.getTarget().getClass().getName());
// System.out.println("被拦截的方法"+joinPoint.getSignature().getName());
// System.out.println("参数:"+ Arrays.toString(joinPoint.getArgs()));
System.out.println("启动事务");
}
public void afterTreturning(JoinPoint joinPoint,Object o){
System.out.println("事务提交");
}
// 只有在运行时才会产生异常,因为运行时才会进行代理
public void afterThrowing(JoinPoint joinPoint,RuntimeException e){
System.out.println("产生了异常,事务回滚"+e.getMessage());
}
public void after(JoinPoint joinPoint){
System.out.println("关闭资源");
}
/**
* 环绕通知,灵活度低,可插拔性低,功能强大
* @param pjp
*/
public void afterAround(ProceedingJoinPoint pjp){
//连接点
System.out.println("开启事务");
try {
Object o = pjp.proceed();
System.out.println("提交事务");
} catch (Throwable e) {
System.out.println("事务回滚");
throw new RuntimeException(e);
}finally {
System.out.println("关闭资源");
}
}
}
连接点:Joinpoint,给一个连接点,对谁进行增强,对应要增强的方法。
切入点: pointcut ,进行功能增强了的方法,没有被增强的不是切入点,是连接点
切面: 是描述通知和切入点的对应关系而组成的,也就是那些通知方法对应那些切入点方法
通知:在切入点前后执行的操作,也就是增强的共性功能,在SpringAOP中,功能最终以方
法的形式呈现。
通知类:通知方法所在的类就叫做通知类
配置核心文件:
<bean id="userService" class="com.csi.service.impl.UserServiceImpl">
<property name="userMapper" ref="userMapper"/>
</bean>
<bean id="userMapper" class="com.csi.mapper.impl.UserMapperImpl"/>
<bean id="txAdvice" class="com.csi.proxy.TransactionManagerAdvice"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.csi.service..*.*(..))"/>
<aop:aspect ref="txAdvice">
<!-- <aop:before method="beforeT" pointcut-ref="pointcut"/>-->
<!-- <aop:after-returning method="afterTreturning" pointcut-ref="pointcut" returning="o"/>-->
<!-- <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/>-->
<!-- <aop:after method="after" pointcut-ref="pointcut"/>-->
<!-- 环绕通知 -->
<aop:around method="afterAround" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
expression(表达式)
execution(语法)
拦截对应方法,里面是*是任意类型
找到子包,子包下的所有类,所有类下的所有参数
expression="execution(*com.csi.service..*.*(..))"
配置通知类
配置->切入点->切面(引用通知 ref ,对功能进行同一增强,所有类中的所有方法)
测试类:
package com.csi;
import com.csi.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestTXManagerAdvice {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService1 = (UserService) ctx.getBean("userService");
userService1.save();
System.out.println();
userService1.list();
}
}
逻辑过程:
通过表达式,找到对应的切入点,切入进去再做拦截,切入service,拦截所有子包里的所有类的所有参数,之后做增强,配置一个增强类,
异常通知,最终通知
此异常最准确的是在运行时产生的异常
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.csi.service.impl.UserServiceImpl.list(..))"/>
<aop:aspect ref="agentAdvice">
<aop:before method="beforeT" pointcut-ref="pointcut"/>
<aop:after-returning method="afterTreturning" pointcut-ref="pointcut" returning="o"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
环绕通知
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.csi.service.impl.UserServiceImpl.list(..))"/>
<aop:aspect ref="agentAdvice">
<!-- <aop:before method="beforeT" pointcut-ref="pointcut"/>-->
<!-- <aop:after-returning method="afterTreturning" pointcut-ref="pointcut" returning="o"/>-->
<!-- <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/>-->
<!-- <aop:after method="after" pointcut-ref="pointcut"/>-->
<!-- 环绕通知 -->
<aop:before method="before" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
事务类,不是覆盖而是包含,环绕包含四种通知类型
package com.csi.proxy;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import java.util.Arrays;
public class TransactionManagerAdvice {
public TransactionManagerAdvice(){
System.out.println("开启数据库连接");
}
public void beforeT(JoinPoint joinPoint){
// System.out.println("被增强的类"+joinPoint.getTarget().getClass().getName());
// System.out.println("被拦截的方法"+joinPoint.getSignature().getName());
// System.out.println("参数:"+ Arrays.toString(joinPoint.getArgs()));
System.out.println("启动事务");
}
public void afterTreturning(JoinPoint joinPoint,Object o){
System.out.println("事务提交");
}
// 只有在运行时才会产生异常,因为运行时才会进行代理
public void afterThrowing(JoinPoint joinPoint,RuntimeException e){
System.out.println("产生了异常,事务回滚"+e.getMessage());
}
public void after(JoinPoint joinPoint){
System.out.println("关闭资源");
}
/**
* 环绕通知,灵活度低,可插拔性低,功能强大
* @param pjp
*/
public void afterAround(ProceedingJoinPoint pjp){
//连接点
System.out.println("开启事务");
try {
Object o = pjp.proceed();
System.out.println("提交事务");
} catch (Throwable e) {
System.out.println("事务回滚");
throw new RuntimeException(e);
}finally {
System.out.println("关闭资源");
}
}
}
权限,到service层去判断,在调用方法之前判断,前置通知
package com.csi.proxy;
import org.aspectj.lang.JoinPoint;
public class AgentManageAdvice {
public void before(JoinPoint joinPoint){
System.out.println("先查数据库是否有权限...");
// if (i==1){}else {throw new RuntimeException("");}
}
}
日期格式注入
日期格式注入
<bean id="address" class="com.csi.domain.Address"/>
<bean id="dateFormat" class="java.text.SimpleDateFormat">
<constructor-arg name="pattern" value="yyyy-MM-dd"/>
</bean>
<bean id="person" class="com.csi.domain.Person">
<constructor-arg name="bornDate">
<bean factory-bean="dateFormat" factory-method="parse">
<constructor-arg value="2022-02-22"/>
</bean>
</constructor-arg>
</bean>
List集合注入
<bean id="student" class="com.csi.domain.Student"/>
<property name="list">
<list>
<value>英语</value>
<value>数学</value>
<value>语文</value>
</list>
</property>
</bean>
Map集合注入
<property name="map">
<map>
<entry key="1" value="1"/>
<entry key="2" value="2"/>
<entry key="3" value="3"/>
</map>
</property>
属性文件注入
属性文件
<property name="properties">
<props>
<prop key="jdbc.className">com.mysql.cg.jdbc.Driver</prop>
<prop key="jdbc.url">jdbc:mysql://test</prop>
<prop key="jdbc.username">root</prop>
<prop key="jdbc.password">root</prop>
</props>
</property>
p标签注入,内部bean注入,ref注入
<bean id="address" class="com.csi.domain.Address"/>
P标签注入少
<bean id="person" class="com.csi.domain.Person " p:address-ref="address" p:age="20" p:hello="world">
</bean>
内部bean注入
<bean id="person" class="com.csi.domain.Person " >
<constructor-arg>
<bean class="com.csi.domain.Address"/>
</constructor-arg>
</bean>
ref注入
<bean id="person1" class="com.csi.domain.Person " >
<constructor-arg name="address" ref="address">
</constructor-arg>
</bean>
两种注入类型 1.property属性注入 2.构造方法注入,少用吧 还有ref