SpringDay02(IOC注解AOP 2种代理方式)

IOC注解方式
1、导入主键开发所需的jar包
    引入IOC容器必须的6个jar包
    多引入一个:Spring框架的AOP的jar包,spring-aop的jar包
2、创建对应的报结构,编写java的类
    UserService    --接口
    UserServiceImp --具体的实现列
3、在src目录下,创建applicationContext.xml的配置文件,然后引入约束。因为使用注解的方式,引入的约束发生变化
    需要引入Context的约束
        <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" 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"> <!-- bean definitions here -->
        </beans>
4、在applicationContext.xml配置文件中开启组件扫描
    Spring的注解开发:组件扫描
    <context:component-scan base-package="my.demo1"></context:component-scan>
    可以采用下面的配置
    <context:component-scan base-package="my"></context:component-scan> 扫描my包下所有的内容

5、在UserService的实现类上添加注解
    @Component(value="userService") 相当于在XML的配置方式中<bean id="userService" class="my.demo1.UserServiceImpl">

6、测试代码
    @Test
    public void run2() {
        //获取工厂,加载配置文件
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取对象
        UserService us = (UserService) ac.getBean("userService");
        us.sayHel();
    }   

Bean管理的常用注解
1@Component组件(作用在类上)
2、Spring中提供@Component的三个衍生注解
    @Controller         作用在web层
    @Service            作用在业务层
    @Repository         作用在持久层

    这三个注解是为了让标注类本身的用途清晰

3、属性注入的注解(可以不用提供set方法)
    如果注入的普通类型,可以使用value注解
        @Value      用于注入普通类型
    如果注入的是对象类型,使用下面的主键
        @Autowired      默认按类型进行自动装配
            如果想按名称注入
                @Qualifier  强制使用名称注入【根据名称找】

    @Resource       相当于@Autowired@Qualifier一起使用
        java提供的注解
        属性使用name属性
Bean的作用范围和生命周期的注解
1、Bean的作用范围注解
    注解为@Scope(value="prototype") 作用在类上,值为:
        singleton       单例,默认值
        prototype       多例
2、Bean的生命周期的配置
    注解如下
        @PostConstruct      相当于init-method
        @PreDestroy         相当于destory-method

JUit单元测试
1、简化JUnit的测试,使用Spring框架也可以整合测试
2、具体步骤
    必须先有JUnit的环境(即已经导入了JUnit4的开发环境)
    一、在程序中引入:spring-test.jar
    二、在具体的测试类上添加注解
        @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration("classpath:applicationContext.xml")
        public class Demo2 {
            @Resource(name="userService")
            private UserService userService;

            @Test
            public void run1() {
                //原来:获取到工厂,加载配置文件,getBean()
                userService.sayHel();
            }
        }

AOP概述
1、AOP的技术
    在软件业中,AOP为Aspect Oriented Programming 面向切面编程
    AOP是一种编程范式,属于软工范畴,知道开发者如何组织程序结构
    AOP最早由AOP联盟的组织提出的,指定了一套规范,Spring将AOP思想引入框架中,必须遵守AOP联盟的规范
    通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
    AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型
    利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提供程序的可重用性,同时提供了开发的效率
2、AOP 面向切面变成(解决OOP遇到一些问题)
3、AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)
4、学习的原因
    可以在不修改代码的前提下,对程序进行增强

AOP的底层实现
1、Spring框架的AOP技术底层也是采用的代理技术,代理的方式有2种
    基于JDK的动态代理
        必须是面向接口的,只要实现了具体接口的类才能生成代理对象
    基于OGLIB动态代理
        对于没有实现了接口的类,也可以产生代理,产生这个类的子类的方式
2、Spring的传统AOP中根据类是否实现接口,采用不同的代理方式
    如果实现类接口,使用JDK动态代理完成AOP
    如果没有实现接口,采用OGLIB动态代理完成AOP

JDK的动态代理【要有接口 ,有接口默认用】
【动态生成 运行期间】
1、使用Proxy类来生成代理对象的一些代码
    public static UserDao  getProxy(final UserDao dao) {
        //使用Proxy类生成代理对象
        UserDao proxy = (UserDao)Proxy.newProxyInstance(dao.getClass().getClassLoader(), dao.getClass().getInterfaces(), new InvocationHandler() {

            //代理对象方法一执行,invoke就会执行一次
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if("save".equals(method.getName())) {
                    System.out.println("记录日志");
                    //开启事务
                }
                //提交事务
                //让dao类的save或者update方法正常的执行
                return method.invoke(dao, args);
            }
        });
        //返回代理对象
        return proxy;
    }

CGLIB的代理技术【类加载的时候生成子类】
1、引入CGLIB的开发包
    如果想使用CGLIB的技术来生成代理对象,那么需要引入CGLIB的开发的jar包,在spring框架核心包中已经引入了CGLIB的开发包了,所以直接引入Spring核心开发包即可

2、相关代码 
    public static BookDaoImpl getProxy() {
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(BookDaoImpl.class);
//      Callback call = null;
        //设置回调函数
        enhancer.setCallback(new MethodInterceptor() {
            //代理对象的方法执行,回调函数就会执行
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                if(method.getName().equals("save")) {
                    System.out.println("记录");
                }
                //正常执行
                return methodProxy.invokeSuper(obj, args);
            }
        });
        //生成代理对象
        BookDaoImpl proxy = (BookDaoImpl) enhancer.create();
        return proxy;
    }

AOP的相关术语
1、Joinpoint(连接点)    所谓连接点是指那些被拦截到的点,在spring中,这些点指的的是方法,因为spring只支持方法类型的连接点
2、Pointcut(切入点)     所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
3、Advice(通知、增强) 所谓通知是指拦截到Joinpoint之后要做的事情就是通知,通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
4、Introduction(引介)  引介是一种特殊的通知,在不修改类代码的前提下,Introduction可以在运行期为类动态添加一些方法或Field
5、Target(目标对象)  代理的目标对象
6、Weaving(织入)       指把增强应用到目标对象来创建新的代理对象的过程
7、Proxy(代理)             一个类被AOP织入增强后,就产生一个结果代理类
8、Aspect(切面)            是切入点和通知的结合,自己来编写和配置

XML方式完成AOP的开发
1、创建JavaWeb项目,引入具体的开发的jar包
    先引入Spring框架开发的基本开发包
    在引入Spring框架的AOP的开发包
        spring的传统的AOP的开发的包
            spring-aop-4.2.4.RELEASE.jar
            com.springsource.org.aopalliance-1.0.0.jar

        aspectJ的开发包
            com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
            spring-aspects-4.2.4.RELEASE.jar
2、创建Spring的配置文件,引入具体的AOP的schema约束
    <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"> <!-- bean definitions here -->
</beans>

3、创建包结构,编写具体的接口和熟悉i暗雷
    my.demo2
        CustomerDao --接口
        CustomerDaoImpl 实现类
4、 将目标类配置到Spring中
    <bean id="customerDao" class="my.demo3.CustomerDaoImpl"></bean>
5、定义切面类
     public class MyAspectXml {
    /**
     * 通知(具体的增强)
     */
    public void log() {
        System.out.println("记录");
    }
}
6、在配置文件中定义切面类
    <bean id="myAspectXml" class="my.demo3.MyAspectXml"></bean>
7、在配置文件中完成aop的配置
    <aop:config>
        <!-- 配置切面类:切入点+通知 -->
        <aop:aspect ref="myAspectXml">
            <!-- 配置前置通知,save方法执行之前,增强的方法会执行 -->
            <!-- 切入点的表达式  execution(public void my.demo3.CustomerDaoImpl.save())-->
            <aop:before method="log" pointcut="execution(public void my.demo3.CustomerDaoImpl.save())"/>
        </aop:aspect>
    </aop:config>
8、完成代码  
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class Demo3 {
        @Resource(name="customerDao")
        private CustomerDao customerDao;
        @Test
        public void run1() {
            customerDao.save();
            customerDao.update();
            customerDao.delete();
        }
    }

切入点的表达式
1、在配置切入点的时候,需要定义表达式,重点的格式execution(public * *(..))
    切入点表达式的格式
        execution([修饰符] 返回值类型 包名.类名.方法名(参数))
    修饰符可以省略不写,不是必须要出现的
    返回值类型是不能省略不写的,根据方法来编写返回值,可以使用*来代替
    包名例如my.my1.demo1.CustomerDaoImpl
        首先my是不能省略不写的,但是可以用*来代替
        中间的包名可以使用*来代替
        如果想省略中间的包名可以使用..

    类名也可以使用*来代替,有类似的 *DaoImpl
    方法也可以使用*来代替
    参数如果是一个参数可以使用*来代替,如果想代表任意参数就用..

AOP的通知类型
1、前置通知
    在目标类的方法执行之前执行
    配置文件信息: <aop:before method="log" pointcut="execution(public void my.demo3.CustomerDaoImpl.save())"/>
     <aop:before method="log" pointcut-ref="mySave"/>
    应用:可以对方法的参数来做校验

2、最终通知
    在目标类的方法执行之后执行,如果程序出现了异常,最终通知也会执行
    配置文件信息:<aop:after method="after" pointcut="execution(public void my.demo3.CustomerDaoImpl.save())"/>
    应用:像释放资源
3、后置通知
    方法正常执行后的通知
    配置文件信息:<aop:after-returning method="afterReturn" pointcut="execution(public void my.demo3.CustomerDaoImpl.save())" />
    应用:修改方法的返回值
4、异常抛出通知
    在抛出异常后的通知
    配置文件信息:<aop:after-throwing method="afterThrowing" pointcut="execution(public void my.demo3.CustomerDaoImpl.save())" />
    应用:包装异常的信息
5、环绕通知
    方法的执行前后执行
    配置文件信息:<aop:around method="around" pointcut="execution(public void my.demo3.CustomerDaoImpl.save())" />
    应用:目标的方法默认不执行,需要使用ProceedingJoinPoint来让目标对象的方法执行

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
applicationContext.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" 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"> <!-- bean definitions here -->
    <!-- 开启注解的扫描 -->
    <context:component-scan base-package="my"></context:component-scan>
</beans>
public class Demo1 {
    /**
     * 原来
     */
    @Test
    public void run1() {
        UserService us = new UserServiceImpl();
        us.sayHel();
    }
    /**
     *注解的方式 
     */
    @Test
    public void run2() {
        //获取工厂,加载配置文件
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取对象
        UserService us = (UserService) ac.getBean("userService");
        us.sayHel();
    }   
}
/**
 * UserDaoImpl交给Ioc的容器
 * @author Administrator
 *
 */
@Repository(value="userDao")
public class UserDaoImpl implements UserDao{

    @Override
    public void save() {
        System.out.println("保存客户");
    }

}
/**
 * 组件注解,标记类
 * <bean id="userService" class="my.demo1.UserServiceImpl"> ==@Component(value="userService")
 * @author Administrator
 */
//@Scope(value="prototype")
@Component(value="userService")
public class UserServiceImpl implements UserService {

    //给name属性注入弱鸡的字符串,setName还可以不用写
    @Value(value="弱鸡")
    private String name;

    //@Autowired按类型自动装配
//  @Autowired
//  @Qualifier(value="userDao") //按名称注入
    //是Java的注解,Spring框架支持该逐渐诶
    @Resource(name="userDao")
    private UserDao userDao;

    @Override
    public void sayHel() {
        System.out.println("hello"+name);
        userDao.save();
    }

    @PostConstruct
    public void init() {
        System.out.println("初始化");
    }

}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo2 {
    @Resource(name="userService")
    private UserService userService;

    @Test
    public void run1() {
        //原来:获取到工厂,加载配置文件,getBean()
        userService.sayHel();
    }
}
<?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: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"> <!-- bean definitions here -->
    <!-- 配置客户的dao -->
    <bean id="customerDao" class="my.demo3.CustomerDaoImpl"></bean>
    <!-- 编写切面类配置好 -->
    <bean id="myAspectXml" class="my.demo3.MyAspectXml"></bean>
    <!-- 配置AOP -->
    <aop:config>
        <!-- 配置切面类:切入点+通知 -->
        <aop:aspect ref="myAspectXml">
            <!-- 配置前置通知,save方法执行之前,增强的方法会执行 -->
            <!-- 切入点的表达式  execution(public void my.demo3.CustomerDaoImpl.save())-->
            <aop:before method="log" pointcut="execution(public void my.demo3.CustomerDaoImpl.save())"/>
        </aop:aspect>
    </aop:config>
</beans>
    <!-- 配置AOP -->
    <aop:config>
        <!-- 配置切面类:切入点+通知 -->
        <aop:aspect ref="myAspectXml">
            <!-- 切入点的表达式
                1、execution() 固定的,必须的
                2、public 可以省略不写
                3、void 返回值可以出现* 表示任意的返回值 ,返回值类型不能不写
                4、可以使用*代替的 ,不能不编写的,简写方式:*..* 表示任意层 一个*一层
                5、*DaoImpl
                6、方法 save*
                7、方法的参数:..表示任意个参数
             --> 
            <!-- <aop:before method="log" pointcut="execution(public void my.demo3.CustomerDaoImpl.save())"/> -->
            <!-- public 可以省略不写 -->
            <aop:before method="log" pointcut="execution(public void my.demo3.CustomerDaoImpl.save())"/> 
            <!-- void 返回值可以出现* 表示任意的返回值 ,返回值类型不能不写  -->
            <aop:before method="log" pointcut="execution(* my.demo3.CustomerDaoImpl.save())"/>
            <!-- 包名可以用*代替 不能不写 -->
            <aop:before method="log" pointcut="execution(* *.demo3.CustomerDaoImpl.save())"/>
            <!-- 包的简写的方式,任意的包的结构 -->
            <aop:before method="log" pointcut="execution(* *..*.CustomerDaoImpl.save())"/>
            <!-- 编写类的写法 -->
            <aop:before method="log" pointcut="execution(* *..*.*DaoImpl.save())"/>
            <!-- 方法的参数:..表示任意个参数 -->
            <aop:before method="log" pointcut="execution(* *..*.*DaoImpl.*save())"/>
            <!-- 参数列表,出现一个*,表示一个参数,任意个参数使用.. -->
            <aop:before method="log" pointcut="execution(* *..*.*DaoImpl.*save(..))"/>
        </aop:aspect>
    </aop:config>
</beans>
<aop:config>
        <!-- 配置切面类:切入点+通知 -->
        <aop:aspect ref="myAspectXml">
            <!-- <aop:before method="log" pointcut="execution(public void my.demo3.CustomerDaoImpl.save())"/> -->
            <!-- 配置最终通知 -->
            <!-- <aop:after method="after" pointcut="execution(public void my.demo3.CustomerDaoImpl.save())"/> -->

            <!-- <aop:after-returning method="afterReturn" pointcut="execution(public void my.demo3.CustomerDaoImpl.save())" /> -->
            <aop:around method="around" pointcut="execution(public void my.demo3.CustomerDaoImpl.save())" />

        </aop:aspect>
    </aop:config>
/**
 * 使用JDK的方式生成代理对象
 * @author Administrator
 *
 */
public class MyProxyUtils {
    public static UserDao  getProxy(final UserDao dao) {
        //使用Proxy类生成代理对象
        UserDao proxy = (UserDao)Proxy.newProxyInstance(dao.getClass().getClassLoader(), dao.getClass().getInterfaces(), new InvocationHandler() {

            //代理对象方法一执行,invoke就会执行一次
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if("save".equals(method.getName())) {
                    System.out.println("记录日志");
                    //开启事务
                }
                //提交事务
                //让dao类的save或者update方法正常的执行
                return method.invoke(dao, args);
            }
        });
        //返回代理对象

        return proxy;
    }
}
public class MyCglibUtils {
    //使用CGLIB方式生成代理的对象
    public static BookDaoImpl getProxy() {
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(BookDaoImpl.class);
//      Callback call = null;
        //设置回调函数
        enhancer.setCallback(new MethodInterceptor() {
            //代理对象的方法执行,回调函数就会执行
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                if(method.getName().equals("save")) {
                    System.out.println("记录");
                }
                //正常执行
                return methodProxy.invokeSuper(obj, args);
            }
        });
        //生成代理对象
        BookDaoImpl proxy = (BookDaoImpl) enhancer.create();
        return proxy;
    }
}
/**
 * 切面类
 * @author Administrator
 *
 */
public class MyAspectXml {
    /**
     * 通知(具体的增强)
     */
    public void log() {
        System.out.println("记录");
    }
    /**
     * 最终通知,方法执行成功或者出现异常,都会执行
     */
    public void after() {
        System.out.println("最终通知");
    }

    /**
     * 方法执行之后,执行后置通知,程序出现了异常,后置通知不会执行的
     */
    public void afterReturn() {
        System.out.println("后置通知");
    }
    /**
     * 环绕通知:方法执行之前和方法执行之后进行通知,默认的情况下,目标对象的方法不能执行,需要手动让目标对象的方法之息
     */
    public void around(ProceedingJoinPoint joinPoint) {
        System.out.println("环绕通知1");
        try {
            //手动让目标对象的方法去执行
            joinPoint.proceed();
        } catch (Throwable e) {

            e.printStackTrace();
        }
        System.out.println("环绕通知2");
    }
}
public class Demo2 {
    @Test
    public void run1() {
        //目标对象
        BookDaoImpl dao = new BookDaoImpl();
        dao.save();
        dao.update();
        System.out.println("-------------");
        //使用CGLIB方式生成代理对象
        BookDaoImpl proxy = MyCglibUtils.getProxy();
        proxy.save();
        proxy.update();
    }
}
/**
 * 测试AOP的功能
 * @author Administrator
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext3.xml")
public class Demo3 {
    @Resource(name="customerDao")
    private CustomerDao customerDao;
    @Test
    public void run1() {
        customerDao.save();
//      customerDao.update();
//      customerDao.delete();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值