AOP面向切面编程及事务管理

AOP面向切面编程及事务管理,第1张

一、AOP:

1、概述:面向切面编程。是通过预编译方式(aspectj)或者运行期动态代理(Spring)实现程序功能的统一维护的技术。

2、作用:在不修改源码的情况下,进行功能增强,通过动态代理进行实现。

3、优势:减少重复代码,提高开发效率,方便维护。

4、AOP的底层实现:Spring的AOP,底层是通过动态代理实现的。在运行期间,通过代理技术动态生成代理对象,代理对象方法执行时进行功能的增强介入,再去调用目标方法,从而完成功能增强。

二、spring的AOP

1、AOP相关概念:

  • 目标对象(Target):要代理的/要增强的目标对象。

  • 代理对象(Proxy):目标对象被AOP织入增强后,就得到一个代理对象

  • 连接点(JoinPoint):能够被拦截到的点,在Spring里指的是方法

    目标类里,所有能够进行增强的方法,都是连接点

  • 切入点(PointCut):要对哪些连接点进行拦截的定义

    已经增强的连接点,叫切入点

  • 通知/增强(Advice):拦截到连接点之后要做的事情

    对目标对象的方法,进行功能增强的代码

  • 切面(Aspect):是切入点和通知的结合

  • 织入(Weaving):把增强/通知 应用到 目标对象来创建代理对象的过程。Spring采用动态代理技术织入,而AspectJ采用编译期织入和装载期织入

AOP开发前要明确的事项

我们要做的事情:

  • 编写核心业务代码(Target目标类的目标方法)

  • 编写通知类,通知类中有通知方法(Advice增强功能方法)

  • 在配置文件中,配置织入关系,即将哪些通知与哪些切入点 结合,形成切面

Spring的AOP做的事情:

  • 生成动态代理的过程(把通知织入到切入点的过程),是由Spring来实现的

  • Spring会监控切入点方法的执行,一旦发现切入点方法执行,使用代理机制动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。

三、基于注解的AOP 快速入门

1、步骤分析

  1. 创建maven项目,导入AOP需要的依赖坐标

  2. 创建目标类,创建通知类

    1. 使用注解@Component标注两个类,配置成为bean对象

    2. 在增强类身上,需要打上注解 @Aspect ,让其成为增强类|对象

    3. 在增强类的方法上,打注解@Before | @AfterReturing | ... 表示想要增强谁。

  3. 在配置文件中,开启组件扫描和AOP的自动代理(自动装配)

  4. 测试

2、代码实现

1、创建maven项目,导入坐标,注意:需要增加AOP的实现包:`aspectjweaver`

    

        
            junit
            junit
            4.12
            test
        

        
            org.springframework
            spring-context
            5.1.12.RELEASE
        

        
            org.springframework
            spring-aop
            5.1.12.RELEASE
        

        
            org.aspectj
            aspectjweaver
            1.9.6
        
    

2、创建目标类和通知类/增强类

public interface UserService {
    void add();
    void update();
}
@Service
public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("调用了UserServiceImpl的add方法");
    }
    @Override
    public void update() {
        System.out.println("调用了UserServiceImpl的aupdate方法");
    }
}
@Aspect //声明成为增强类
@Component //标注成为bean对象
public class Myadvice {

    @Before("execution(* com.itheima..*..*(..))")
    public void sprint() {
        System.out.println("打印了日志-----");
    }

3、编写核心配置类

@Configuration //标注成为核心配置类
@ComponentScan("com.itheima")  //开启组件扫描
@EnableAspectJAutoProxy //允许AOP的自动配置
public class AppConfig {

}

4、编写测试方法

@RunWith(SpringJUnit4ClassRunner.class) //用在测试类上,用于声明不再使用Junit,而是使用Spring提供的运行环境
//Spring提供了单元测试的运行环境:SpringJunit4ClassRunner
@ContextConfiguration(classes = AppConfig.class)//用于指定核心配置类
public class TestUserServiceImpl {
    @Autowired
    private UserService us;
    @Test
        public void test(){
        us.add();
    }
}
注解解释:

1、通知的类型:

注意:

  • 注解方式配置的通知,执行顺序是:前置->最终->后置/异常

  • 如果想要指定执行的顺序,就使用环绕通知 , 因为环绕增强是由我们手动控制的

2、切点表达式

语法:execution ( [ 权限修饰符 ]   返回值类型  包名 . 类名 . 方法名 ( 参数列表 ) )

修饰符:可省略

返回值类型:进行类型指定,如String等。*表示任意修饰符,

包名:可以写【.】,代表当前目录的下一级文件。写【..】,代表当前包下的任意级类或包

类名:可指定类名,【*】代表任意字符

方法名:可以指定方法名,【*】代表任意字符

参数:可以指定类型,如string,integer。【..】代表任意类型,任意个数的参数

示例:

execution(public void com.itheima.dao.impl.UserDao.save())

execution(* com.itheima.dao..*.*(..))

三、spring事务管理

1、概念:

所谓事务管理,即:按照给定的事务规则,来执行提交或回滚 *** 作。其中:

  • "给定的事务规则":用TransactionDefinition表示

  • "按照..来执行提交或回滚 *** 作":用PlatformTransactionManager来完成

  • TransactionStatus用于表示一个运行着的事务的状态

快速入门:

需求:

1、完成一个银行转账功能

2、定义dao和service层,完成扣钱和加钱的功能

3、注册事务管理,并在类上添加事务注解

代码:

1、编写dao层和service层

public interface AccountDao {
    @Update("update account set money = money - #{money} where name = #{from}")
    void kouqian(@Param("from") String from, @Param("money") int money);

    @Update("update account set money = money + #{money} where name = #{to}")
    void jiaqian(@Param("to") String to, @Param("money") int money);
}
public interface AccountService {

    public void zhuanzhang(String from,String to,int money);
}
@Transactional//类里面的方法都有事务
@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao dao;
    public void zhuanzhang(String from, String to, int money) {
        dao.kouqian(from, money);
        int a = 1 / 0;//在扣钱后编写一个错误,运行后查看数据库扣钱和加强是否同步
        dao.jiaqian(to, money);
    }
}

2、编写核心配置类

@Configuration //声明此类是核心配置类
@ComponentScan("com.itheima") //开启组件扫描
@PropertySource("db.properties") //获取properties文件
@EnableTransactionManagement  //开启事务的注解驱动

public class AppConfig {
    @Value("${db.driverClassName}")
    private String driverClassName;

    @Value("${db.url}")
    private String url;

    @Value("${db.username}")
    private String username;

    @Value("${db.password}")
    private String password;

    @Bean
    public DataSource ds() {
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driverClassName);
        ds.setUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);

        return ds;
    }

    @Bean
    public SqlSessionFactoryBean factory(DataSource ds) {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(ds);
        return factory;
    }

    @Bean
    public static MapperScannerConfigurer msc() {
        MapperScannerConfigurer configurer = new MapperScannerConfigurer();
        configurer.setBasePackage("com.itheima.dao");
        return configurer;
    }

    @Bean
    public DataSourceTransactionManager tm(DataSource ds) {
        DataSourceTransactionManager tm = new DataSourceTransactionManager();
        tm.setDataSource(ds);
        return tm;
    }
}

3、编写测试方法

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class TestAccountServiceImpl {
    @Autowired
    private AccountService as;
    @Test
        public void test(){

        as.zhuanzhang("zs","ls",100);
    }
}

4、进行测试,在扣钱方法后添加错误,运行后查看数据库金额的增减是否同步。

 

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/799711.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-06
下一篇 2022-05-06

发表评论

登录后才能评论

评论列表(0条)

保存