Spring系列
- Spring — Spring简介、入门、配置 , IoC和DI思想
- Spring — IoC核心(基于XML)、DI核心(基于XML)
- Spring — 使用IoC和DI模拟注册案例、注解配置IoC和DI
- Spring — 静态代理、动态代理、拦截器思想
- Spring — AOP思想、AOP开发、Pointcut语法、注解配置AOP
- Spring — DAO层、Spring JDBC、Spring事务控制
- Spring — XML配置事务、注解+XML、纯注解的配置方式
- Spring整合MyBatis
- Spring Java Config — 组件注册相关注解
- Spring Java Config — 常用注解
在开发中,为了给业务方法中增加日志记录,权限检查,事务控制等功能,此时我们需要去修改业务方法代码,考虑到代码的重用性,我们可以考虑使用OOP的继承或组合关系
来消除重复, 但是无论怎么样, 我们都会在业务方法中纵向地增加这些功能方法的调用代码。
此时,既不遵循开闭原则
,也会为后期系统的维护带来很大的麻烦。这些零散存在于业务方法中的功能代码,我们称之为横切面关注点,横切面关注点不属于业务范围,应该从业务代码中剥离出来。为了解决该问题, OOP思想是不行了,得使用AOP思想。
AOP(Aspect Oritention Programming):
把一个个的横切关注点
放到某个模块中去,称之为切面。那么每一个的切面都能影响业务的某一种功能,切面的目的就是功能增强,如日志切面就是一个横切关注点,应用中许多方法需要做日志记录的只需要插入日志的切面即可。
这种面向切面编程的思想就是AOP思想;
跳转到目录
Joinpoint : 连接点,被拦截到需要被增强的方法。where :去哪里做增强
Pointcut : 切入点,哪些包中的哪些类中的哪些方法,可认为是连接点的集合。where:去哪些地方做增强
Advice : 增强,当拦截到Joinpoint之后,在方法执行的什么时机( when )做什么样(what)的增强。根据时机分为:前置增强、后置增强、异常增强、最终增强、环绕增强;
Aspect : 切面, Pointcut+ Advice ,去哪些地方+在什么时机+做什么增强
Target : 目标对象,被代理的目标对象
Weaving : 织入,把Advice加到Target.上之后,创建出Proxy对象的过程。
Proxy : 一个类被AOP织入增强后,产生的代理类
Advice : (增强)执行时机:
跳转到目录
AOP的规范本应该由SUN公司提出,但是被AOP联盟捷足先登。AOP联盟在制定AOP规范时,首先就要解决一个问题: 怎么表示切入点。也就是说怎么表达需要在哪些方法上做增强。这是一个如何表示WHERE的问题。
AOP规范后,面向切面编程的框架AspectJ也就应运而生了, 同时也确定如何去表达这个WHERE。
(表示在哪些包下的哪些类中的哪些方法上做切入增强)
:execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)throws-pattern?)
execution(<修饰符>? <返回类型> <声明类型>? <方法名><参数>) <异常>?)
? 表示可写可不写
*
: 匹配任何部分,但是只能表示一个单词
..
: 可用于全限定名中和方法参数中,分别表示 包以及子包 和 0到N个参数。
常见的写法:(对应表达式从后往前看)
execution(* cn.sunny.wms.service.*.*(..))
: 表示对service包下的所有类所有方法做增强
execution(* cn.sunny.wms.service.*Serice.*(..))
: 表示对service包下所有以Service为后缀的类的所有方法做增强
execution(* cn.sunny..service.*Service.*(..)
: 表示对sunny包及其子包下的service包中的以Service为后缀的类的所有方法做增强
跳转到目录
跳转到目录
首先导入AOP织入–>Maven依赖
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.4version>
dependency>
跳转到目录
代码
// domain
public class Employee1 {
}
// ----------------------------------------------
// dao包
public interface EmployeeDao1 {
void save(Employee1 emp);
void update(Employee1 emp);
}
public class EmployeeDaoImpl1 implements EmployeeDao1 {
public void save(Employee1 emp) {
System.out.println("保存员工");
}
public void update(Employee1 emp) {
System.out.println("修改员工信息");;
}
}
// ----------------------------------------------
// service包
public interface EmployeeService1 {
void save(Employee1 emp);
void update(Employee1 emp);
}
public class EmployeeServiceImpl1 implements EmployeeService1 {
private EmployeeDao1 dao1;
public void setDao1(EmployeeDao1 dao1) {
this.dao1 = dao1;
}
public void save(Employee1 emp) {
dao1.save(emp);
System.out.println("保存成功");
}
public void update(Employee1 emp) {
dao1.update(emp);
throw new RuntimeException("故意出错");
}
}
// ----------------------------------------------
// 事务管理器(模拟)
public class TransactionManager2 {
public void begin(){
System.out.println("开启事务");
}
public void commit(){
System.out.println("提交事务");
}
public void rollback(){
System.out.println("回滚事务");
}
public void close(){
System.out.println("释放资源");
}
}
xml文件
<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 https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="employeeDao1" class="com.sunny._02_dynamic_proxy.dao.impl.EmployeeDaoImpl1"/>
<bean id="employeeService1" class="com.sunny._02_dynamic_proxy.service.impl.EmployeeServiceImpl1">
<property name="dao1" ref="employeeDao1"/>
bean>
<bean id="transactionManager2" class="com.sunny._02_dynamic_proxy.tx.TransactionManager2"/>
<aop:config >
<aop:aspect ref="transactionManager2">
<aop:pointcut id="txPoint"
expression="execution(* com.sunny._02_dynamic_proxy.service.*Service1.*(..))"/>
<aop:before method="begin" pointcut-ref="txPoint"/>
<aop:after-returning method="commit" pointcut-ref="txPoint"/>
<aop:after-throwing method="rollback" pointcut-ref="txPoint"/>
<aop:after method="close" pointcut-ref="txPoint"/>
aop:aspect>
aop:config>
beans>
测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class JdkDynamicProxyTest {
// com.sun.proxy.$Proxy14
@Autowired
private EmployeeService1 service1;
@Test
public void testSave(){
System.out.println(service1.getClass());
service1.save(new Employee1());
}
@Test
public void testUpdate(){
service1.update(new Employee1());
}
}
跳转到目录
代码
// TransactionManager类
public class TransactionManager1 {
// 使用JoinPoint类获取被增强方法的信息
// 必须作为增强方法的第一个参数
public void begin(JoinPoint jp){
System.out.println("代理对象:" + jp.getThis().getClass());
System.out.println("目标对象:" + jp.getTarget().getClass());
System.out.println("被增强方法的参数:" + Arrays.toString(jp.getArgs()));
System.out.println("连接点方法签名:" + jp.getSignature());
System.out.println("当前连接点的类型:" + jp.getKind());
System.out.println("开启事务");
}
public void commit(JoinPoint jp){
System.out.println("提交事务");
}
public void rollback(JoinPoint jp, Throwable exception){
System.out.println("回滚事务: " + "异常信息:" + exception);
}
public void close(JoinPoint jp){
System.out.println("释放资源");
}
public Object aroundMethod(ProceedingJoinPoint jpj){
Object ret = null;
System.out.println("开启事务");
try {
//System.out.println(".....执行真实对象中的方法");
ret = jpj.proceed(); // 调用真实对象的方法
System.out.println("提交事务");
} catch (Throwable e){
System.out.println("回滚事务:" + "异常信息:" + e.getMessage());
} finally {
System.out.println("释放资源");
}
return ret;
}
}
xml文件
<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 https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="employeeDao1" class="com.sunny._02_dynamic_proxy.dao.impl.EmployeeDaoImpl1"/>
<bean id="employeeService1" class="com.sunny._02_dynamic_proxy.service.impl.EmployeeServiceImpl1">
<property name="dao1" ref="employeeDao1"/>
bean>
<bean id="transactionManager1" class="com.sunny._02_dynamic_proxy.tx.TransactionManager1"/>
<aop:config >
<aop:aspect ref="transactionManager1">
<aop:pointcut id="txPoint"
expression="execution(* com.sunny._02_dynamic_proxy.service.*Service1.*(..))"/>
<aop:around method="aroundMethod" pointcut-ref="txPoint"/>
aop:aspect>
aop:config>
beans>
跳转到目录
// domain
public class Employee1 {
}
// ----------------------------------------------
// dao包
public interface EmployeeDao1 {
void save(Employee1 emp);
void update(Employee1 emp);
}
@Repository
public class EmployeeDaoImpl1 implements EmployeeDao1 {
public void save(Employee1 emp) {
System.out.println("保存员工");
}
public void update(Employee1 emp) {
System.out.println("修改员工信息");;
}
}
// ----------------------------------------------
// service包
public interface EmployeeService1 {
void save(Employee1 emp);
void update(Employee1 emp);
}
@Service
public class EmployeeServiceImpl1 implements EmployeeService1 {
@Autowired
private EmployeeDao1 dao1;
public void save(Employee1 emp) {
dao1.save(emp);
System.out.println("保存成功");
}
public void update(Employee1 emp) {
dao1.update(emp);
throw new RuntimeException("故意出错");
}
}
// ----------------------------------------------
// 事务管理器(模拟)
@Component // IoC注解
@Aspect // 配置一个切面
public class TransactionManager1 {
// 配置在哪些包中的哪些类中的哪些方法上做增强
//XML:
@Pointcut("execution(* com.sunny._02_dynamic_proxy.service.*Service1.*(..))")
public void txPoint(){
}
@Before("txPoint()")
public void begin(JoinPoint jp){
System.out.println("开启事务");
}
@AfterReturning("txPoint()") // 操作完成之后
public void commit(){
System.out.println("提交事务");
}
@AfterThrowing(value = "txPoint()", throwing = "exception")
public void rollback(Throwable exception){
System.out.println("回滚事务: " + "异常信息:" + exception);
}
@After("txPoint()")
public void close(){
System.out.println("释放资源");
}
//@Around("txPoint()") // 可以替代上面的几个注解
public Object aroundMethod(ProceedingJoinPoint jpj){
Object ret = null;
System.out.println("开启事务");
try {
//System.out.println(".....执行真实对象中的方法");
ret = jpj.proceed(); // 调用真实对象的方法
System.out.println("提交事务");
} catch (Throwable e){
System.out.println("回滚事务:" + "异常信息:" + e.getMessage());
} finally {
System.out.println("释放资源");
}
return ret;
}
}
xml文件
<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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.sunny._02_dynamic_proxy"/>
<aop:aspectj-autoproxy/>
beans>