05-Spring02-AOP

今日知识

1. AOP
2. AspectJ
3. JdbcTemplate

AOP

1. AOP :Aspect Oriented Programming,意为面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
    1. 好处
        * 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
        * AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
        * 经典应用:事务管理,性能监视,安全检查,缓存,日志。
        * SpringAOP使用纯的java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码
        * AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入
2. AOP实现原理  
    1. AOP底层将采用代理机制进行实现
    2. 接口+实现类:Spring采用jdk的动态代理Proxy
    3. 实现类:Spring采用cglib字节码增强
3. AOP术语
    1. target:目标类,需要被代理的类。例如:UserService
    2. Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法
    3. PointCut 切入点:已经被增强的连接点。例如:addUser()
    4. advice 通知/增强,增强代码。例如:after、before
    5. Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程.
    6. proxy 代理类
    7. Aspect(切面): 是切入点pointcut和通知advice的结合
	一个线是一个特殊的面。
	一个切入点和一个通知,组成成一个特殊的面。
4. 手动代理
    1. JDK动态代理
        * 和原来的方法一样
    2. cglib增强字节码 
        1. 导入jar包:
        2. 没有接口,只有实现类。
        //cglib代理
    @Test
    public void test2(){
        final UserService1 userService=new UserService1();

        UserService1 proxy = (UserService1) Enhancer.create(UserService1.class, new InvocationHandler() {
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {

                System.out.println("开启事务");
                Object invoke = method.invoke(userService, objects);
                System.out.println("提交事务");
                return invoke;
            }
        });

        proxy.addUser();
    }
5. Spring编写代理半自动
    1. jar
    2. 目标类
        * public class UserService1 {
        public void addUser() {
            System.out.println("添加用户");
        }
    }
    3. 切面类
        * public class MyAspect2  implements MethodInterceptor{
        public Object invoke(MethodInvocation mi) throws Throwable {
    
            System.out.println("开启事务");
            Object invoke = mi.proceed();
            System.out.println("提交事务");
            return invoke;
        }
    }
    4. spring配置
        * <!--业务类-->
        <bean id="userService" class="com.rqy.service.UserService1"/>
        <!--切面类-->
        <bean id="myAspect" class="com.rqy.aspect.MyAspect2"/>
        <!--使用工厂bean创建代理-->
        <bean id="proxyService" class="org.springframework.aop.framework.ProxyFactoryBean">
            <property name="target" ref="userService"/>
            <property name="interceptorNames" value="myAspect"/>
         
        </bean>
    5. test
        *  @Autowired
        @Qualifier("proxyService")
        UserService1 userService;
        @Test
        public void test3(){
            userService.addUser();
        }
6. Spring编写代理半自动升级版(通过配置类方式,同时注解注入)
    1. jar
    2. 目标类
        @Component("userService")
        * public class UserService1 {
        public void addUser() {
            System.out.println("添加用户");
        }
    }
    3. 切面类
        * //注解注入
        * @Component("mymethod")
        * public class MyAspect2  implements MethodInterceptor{
        public Object invoke(MethodInvocation mi) throws Throwable {
    
            System.out.println("开启事务");
            Object invoke = mi.proceed();
            System.out.println("提交事务");
            return invoke;
        }
    }
    4. 配置类
        * //告诉spring这是一个配置类
        @Configuration
    public class SpringConfig {
        //在配置中注册组件
        //注册第三方或者已经编译过得类
        //如果bean里面不写,默认方法名当做bean的id
        @Bean("proxyFactoryBean")
        public ProxyFactoryBean proxyFactoryBean(@Qualifier("userService") UserService userService){
    
            ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
            proxyFactoryBean.setTarget(userService);
            proxyFactoryBean.setInterceptorNames("mymethod");
            return proxyFactoryBean;
        }
    }
    5. spring配置
        *<!--注解开关-->
        <context:component-scan base-package="com.rqy"/>
    5. test
        * @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration("classpath:application.xml")
        public class MyTest {
        
            @Autowired
            @Qualifier("proxyFactoryBean")
            UserService userService;
            @Test
            public void test(){
                userService.addUser();
            }
        }

AspectJ全自动编程

1. 导包
    * dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>
2. 切面类
    public class MyAspect  implements MethodInterceptor{

    public Object invoke(MethodInvocation mi) throws Throwable {

        System.out.println("开启事务");
        Object invoke = mi.proceed();
        System.out.println("提交事务");
        return invoke;
    }
}
Spring的AOP配置
    * <!--切面类-->
    <bean id="myAspect" class="com.rqy.aspect.MyAspect"/>
    <!--
    AOp编程步骤
        1. 导入命名空间
        2. proxy-target-class="true" 默认使用cglib代理
        3. aop:pointcut
                切入点表达式:execution(* com.rqy.*.*(..))
                              选择方法  包 类名任意 方法名任意  参数任意
                切入面:advice-ref:通知
                       pointcut-ref:切入点的引入
    -->
    <aop:config proxy-target-class="true">
        <aop:pointcut id="myPointCut" expression="execution(* com.rqy.service.*.*(..))"/>
        <aop:advisor advice-ref="myAspect" pointcut-ref="myPointCut"/>
    </aop:config>
3. 测试
    * @Autowired
    @Qualifier("userService")
    UserService userService;
    @Test
    public void test(){
        userService.addUser();

    }

AspectJ

1. AspectJ简介
    * AspectJ是一个基于Java语言的AOP框架
    * Spring2.0以后新增了AspectJ切点表达式的支持
    * @AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面
    * 新版本Spring框架,建议使用AspectJ方式来开发AOP
    * 主要用途:自定义开发
2. Aspect案例讲解
    1. 导包
      	* AOP联盟规范:aopalliance
     	* AOP实现:spring-aop
     	* 规范:aspectjweaver
     	* aspectj实现:spring-aspects
    2. 实现类:和上面一样
    3. 切面类:
        * public class MyAspect2 {
    public void myBefore(JoinPoint jp){
        System.out.println("前置通知"+jp.getSignature().getName());//连接点的方法名
    }
    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("环绕通知 前");
            //获取切入点方法名
            String name = joinPoint.getSignature().getName();
            System.out.println(name);
            Object proceed = joinPoint.proceed();
            System.out.println("环绕通知 后");
            return proceed;
    }
    public void myAfterReturnning(JoinPoint jp,Object e){
        System.out.println("后置通知:"+e);
    }
    public void myAfterThrowing(JoinPoint jp,Throwable e){
        System.out.println("异常通知:"+e.getMessage());
    }
    public void myAfter(){
        System.out.println("最终通知");
    }
}
    4. spring配置
        * <!--业务类-->
    <bean id="userService" class="com.rqy.service.UserService"/>
    <!--切面类-->
    <bean id="myAspect" class="com.rqy.aspect.MyAspect2"/>
    <!--
    AOp编程步骤
        1. 导入命名空间
        2. proxy-target-class="true" 默认使用cglib代理
        3. aop:pointcut
                切入点表达式:execution(* com.rqy.*.*(..))
                              选择方法  包 类名任意 方法名任意  参数任意
                切入面:advice-ref:通知
                       pointcut-ref:切入点的引入
    -->
   <!-- <aop:config proxy-target-class="true">
        <aop:pointcut id="myPointCut" expression="execution(* com.rqy.service.*.*(..))"/>
        <aop:advisor advice-ref="myAspect" pointcut-ref="myPointCut"/>
    </aop:config>-->
     <aop:config>
    <aop:aspect ref="myAspect">
        <aop:pointcut id="myPoinrCut" expression="execution(* com.rqy.service.*.*(..))"/>
        <!--前置通知-->
        <aop:before method="myBefore" pointcut-ref="myPoinrCut"></aop:before>
        <!--环绕通知-->
        <aop:around method="myAround" pointcut-ref="myPoinrCut"></aop:around>
        <!--异常通知-->
        <aop:after-throwing method="myAfterThrowing" pointcut-ref="myPoinrCut" throwing="e"></aop:after-throwing>
       <!--后置通知,用于获取返回值-->
        <aop:after-returning method="myAfterReturnning" pointcut-ref="myPoinrCut" returning="e"></aop:after-returning>
        <!--最终通知 有没有异常都会走最终通知-->
        <aop:after method="myAfter" pointcut-ref="myPoinrCut"></aop:after>
    </aop:aspect>
</aop:config>
3. AspectJ基于xml的讲解
    1. 上面的案例
4. AspectJ注解的讲解
    1. @Aspect  声明切面,修饰切面类,从而获得 通知。
	2. @Before 前置
	3. @AfterReturning 后置
	4. @Around 环绕
	5. @AfterThrowing 抛出异常
	6. @After 最终
    7. 切入点 ,@PointCut ,修饰方法 private void xxx(){}  之后通过“方法名”获得切入点引用
    8. xml需要开启 <!--aop注解生效-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    9. 案例
        @Component
@Aspect
public class MyAspect3 {
    //声明共用切入点
    @Pointcut("execution(* com.rqy.service.*.*(..))")
    public void myPointCut(){

    }
    @Before(value = "myPointCut()")
    public void myBefore(JoinPoint jp){
        System.out.println("前置通知"+jp.getSignature().getName());//连接点的方法名
    }

    @Around(value = "myPointCut()")
    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕通知 前");
        //获取切入点方法名
        String name = joinPoint.getSignature().getName();
        System.out.println(name);
        Object proceed = joinPoint.proceed();
        System.out.println("环绕通知 后");
        return proceed;
    }
    @AfterReturning(value = "myPointCut()",returning = "e")
    public void myAfterReturnning(JoinPoint jp,Object e){
        System.out.println("后置通知:"+e);
    }
    @AfterThrowing(value = "myPointCut()",throwing = "e")
    public void myAfterThrowing(JoinPoint jp,Throwable e){
        System.out.println("异常通知:"+e.getMessage());
    }
    @After(value = "myPointCut()")
    public void myAfter(){
        System.out.println("最终通知");
    }
}

切入点表达式

1. 语法:execution(修饰符  返回值  包.类.方法名(参数) throws异常)
2. 修饰符,一般省略
	public		公共方法
	*			任意
返回值,不能省略
	void			返回没有值
	String		返回值字符串
	* 			任意
包,[省略]
	com.gyf.crm			固定包
	com.gyf.crm.*.service	crm包下面子包任意 (例如:com.gyf.crm.staff.service)
	com.gyf.crm..			crm包下面的所有子包(含自己)
	com.gyf.crm.*.service..	crm包下面任意子包,固定目录service,service目录任意包
类,[省略]
	UserServiceImpl			指定类
	*Impl					以Impl结尾
	User*					以User开头
	*						任意
方法名,不能省略
	addUser					固定方法
	add*						以add开头
	*Do						以Do结尾
	*						任意
(参数)
	()						无参
	(int)						一个整型
	(int ,int)					两个
	(..)						参数任意
throws ,可省略,一般不写。
3. 案例1:
execution(* com.gyf.crm.*.service..*.*(..))

案例2:或
<aop:pointcut expression="execution(* com.gyf.crm.service.*.*(..)) || 
                          execution(* com.gyf.*Do.*(..))" id="myPointCut"/>

JdbcTemplate

1. 导包
    1. 数据库驱动包
    2. Spring对数据库支持的两个包
        * spring-jdbc-4.2.4.RELEASE
        * spring-tx-4.2.4.RELEASE
    3. +1连接池 c3p0 一个 (或者JDBC 两个)
        * c3p0一个包
        * 或者 dbcp包+pool包
2. @Test
    public void test(){
        //1.创建数据源
        BasicDataSource dataSource=new BasicDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/spring_day04?serverTimezone=UTC");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");

        //创建模板
        JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
        String sql="insert into t_user values (null,?,?)";
        jdbcTemplate.update(sql,"tom","123");

    }
3. xml配置的方式(DBCP)
    * <!--dbcp数据源-->
    <bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring_day04?serverTimezone=UTC"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <bean id="userDao" class="com.rqy.dao.impl.UserDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>
4. xml配置的方式(C3P0)
    * <!--c3p0数据源
    参数不太一样
    -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_day04?serverTimezone=UTC"/>
        <property name="user" value="root"/>
        <property name="password" value="123456"/>
    </bean>
5. UserDaoImpl类
    * public class UserDaoImpl implements UserDao {
    JdbcTemplate jdbcTemplate;

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public void addUser(User user) {
        String sql="insert into t_user values (null,?,?)";
        jdbcTemplate.update(sql,user.getUsername(),user.getPassword());
    }
}
6. 使用JdbcDaoSupport(优化Bean配置)
    1. 每个DAO都需要声明template 而且要写set方法。所以让DAO继承与该类,不用写这部分代码了
    2. dao层变化
        * public class UserDaoImpl  extends JdbcDaoSupport implements UserDao {
        public void addUser(User user) {
            String sql="insert into t_user values (null,?,?)";
            this.getJdbcTemplate().update(sql,user.getUsername(),user.getPassword());
        }
    }
    3. xml配置的方式
        *  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_day04?serverTimezone=UTC"/>
        <property name="user" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    <bean id="userDao" class="com.rqy.dao.impl.UserDaoImpl">
        <property name="dataSource" ref="dataSource"/>
    </bean>
posted @ 2019-07-31 17:41  励志前行  阅读(173)  评论(0编辑  收藏  举报