美文网首页
Spring 入门2

Spring 入门2

作者: LiuliuZhang | 来源:发表于2018-05-29 16:46 被阅读0次

    1 使用注解方式

    1.1 配置applicationContext

    添加xmlns:context="http://www.springframework.org/schema/context"约束,配置扫描包的路径

    <!-- 指定扫描com.ibso.bean报下的所有类中的注解.
         注意:扫描包时.会扫描指定报下的所有子孙包
     -->
    <context:component-scan base-package="com.ibso.bean"></context:component-scan>
    

    1.2 创建相关类

    创建user类如下

    //<bean name="user" class="cn.itcast.bean.User"  />
    //@Component("user")
    //  @Service("user") // service层
    //  @Controller("user") // web层
        @Repository("user")// dao层
    //指定对象的作用范围
    @Scope(scopeName="singleton")
    public class User {
        private String name;
        @Value("18")
        private Integer age;
        
        //@Autowired //自动装配
        //问题:如果匹配多个类型一致的对象.将无法选择具体注入哪一个对象.
        //@Qualifier("car2")//使用@Qualifier注解告诉spring容器自动装配哪个名称的对象
        
        @Resource(name="car")//手动注入,指定注入哪个名称的对象
        private Car car;
    
    ......
        @PostConstruct //在对象被创建后调用.init-method
        public void init(){
            System.out.println("我是初始化方法!");
        }
        @PreDestroy //在销毁之前调用.destory-method
        public void destory(){
            System.out.println("我是销毁方法!");
        }
    ......
    

    1.2.1 @Component

    组件,作用在类上,相当于<bean name="user" class="cn.itcast.bean.User"/>
    Spring 中提供 @Component 的三个衍生注解 ,这三个注解是为了让标类本身的用途清晰:( 功能目前来讲是一致的 )

    • @Controller :WEB 层
    • @Service :业务层
    • @Repository :持久层

    1.2.2 @scope

    指定对象的作用范围,@Scope(scopeName="singleton")

    1.2.3 属性注入

    @Value :用于注入普通类型 .
    @Autowired :自动装配 :
    * 默认按类型进行装配 .
    * 按名称注入 : @Qualifier: 强制使用名称注入 .
    @Resource 相当于 : * @Autowired 和@Qualifier 一起使用 .

    1.2.4 生命周期

    @PostConstruct:相当于init-method
    @PreDestroy:相当于destroy-method

    1.2.5 注解与xml方式比较

    2 Spring Junit 测试

    引入spring-test包,指定@RunWith(SpringJUnit4ClassRunner.class)junit将会为我们创建spring容器,@ContextConfiguration制定了配置文件,@Resource(name="user")将bean对象注入到框架中来

    //帮我们创建容器
    @RunWith(SpringJUnit4ClassRunner.class)
    //指定创建容器时使用哪个配置文件
    @ContextConfiguration("classpath:applicationContext.xml")
    public class Demo {
        //将名为user的对象注入到u变量中
        @Resource(name="user")
        private User u;
        
        @Test
        public void fun1(){     
            System.out.println(u);      
        }   
        @Test
        public void fun2(){     
            System.out.println(u);      
        }   
        @Test
        public void fun3(){     
            System.out.println(u);
        }
    }
    

    3 AOP

    3.1 AOP思想介绍

    AOP思想:横向重复,纵向抽取。
    AOP对程序进行增强,不修改源码的情况下,AOP可以进行权限校验,日志记录,性能监控,事务控制.
    例如在多个service中,每个都要解决乱码问题,Filter的出现可以切入到所有service层,在Filter中直接解决乱码问题
    再比如多个service中,每个都需要管理事务,通过InovationHandler可以统一管理事务
    newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

    3.2 Spring AOP

    Spring能为容器中管理的对象生产动态代理对象
    以前使用动态代理,我们需要手动调用Proxy.newProxyInstance(x,x,x)生成代理对象
    Spring的AOP的底层用使用两种代理机制:
    * JDK动态代理:针对实现了接口的类产生代理,被代理对象必须要实现接口
    * Cglib动态代理:针对没有实现接口的类产生代理,生成当前类的子类对象,如果对象被final修饰将无法代理
    动态代理实现
    创建interface

    public interface UserService {
        void save();
        void delete();
        void update();
        void find();
    }
    

    创建实现类

    public class UserServiceImpl implements UserService {
        @Override
        public void save() {
            System.out.println("保存用户!");
            //int i = 1/0;
        }
        @Override
        public void delete() {
            System.out.println("删除用户!");
        }
        @Override
        public void update() {
            System.out.println("更新用户!");
        }
        @Override
        public void find() {
            System.out.println("查找用户!");
        }
    }
    

    JDK动态代理实现,创建UserServiceProxyFactory实现InvocationHandler接口,getUserServiceProxy方法创建代理对象,重写invoke方法,method.invoke(us, arg2);将调用原方法,在这段代码前后可以添加增强的代码

    public class UserServiceProxyFactory implements InvocationHandler {
        
        public UserServiceProxyFactory(UserService us) {
            super();
            this.us = us;
        }
        private UserService us; 
        public UserService getUserServiceProxy(){
            //生成动态代理
            UserService usProxy = (UserService) Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(),
                                        UserServiceImpl.class.getInterfaces(), 
                                        this);
            //返回
            return usProxy;     
        }
        @Override
        public Object invoke(Object arg0, Method method, Object[] arg2) throws Throwable {
            System.out.println("打开事务!");
            Object invoke = method.invoke(us, arg2);
            System.out.println("提交事务!");
            return invoke;
        }
    }
    

    编写测试方法,通过代理对象usProxy调用save方法

        @Test
        //动态代理
        public void fun1(){
            UserService us = new UserServiceImpl();
            UserServiceProxyFactory factory = new UserServiceProxyFactory(us);      
            UserService usProxy = factory.getUserServiceProxy();
            
            usProxy.save();
            //代理对象与被代理对象实现了相同的接口
            //代理对象 与 被代理对象没有继承关系
            System.out.println(usProxy instanceof UserServiceImpl );//false
        }
    

    cglib代理实现,创建UserServiceProxyFactory实现MethodInterceptor接口,重写intercept方法,methodProxy.invokeSuper(prxoyobj, arg);调用原方法,在这段代码前后可以添加增强的代码

    public class UserServiceProxyFactory2 implements MethodInterceptor {
        
    
        public UserService getUserServiceProxy(){
            
            Enhancer en = new Enhancer();//帮我们生成代理对象    
            en.setSuperclass(UserServiceImpl.class);//设置对谁进行代理      
            en.setCallback(this);//代理要做什么       
            UserService us = (UserService) en.create();//创建代理对象     
            return us;
        }
        @Override
        public Object intercept(Object prxoyobj, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable {
            //打开事务
            System.out.println("打开事务!");
            //调用原有方法
            Object returnValue = methodProxy.invokeSuper(prxoyobj, arg);
            //提交事务
            System.out.println("提交事务!");        
            return returnValue;
        }
    }
    

    编写测试方法

        public void fun2(){     
            UserServiceProxyFactory2 factory = new UserServiceProxyFactory2();      
            UserService usProxy = factory.getUserServiceProxy();        
            usProxy.save();     
            //判断代理对象是否属于被代理对象类型
            //代理对象继承了被代理对象=>true
            System.out.println(usProxy instanceof UserServiceImpl );//true
        }
    

    3.3 AOP名词介绍

    Joinpoint(连接点):目标对象中所有可以增强的方法,如上面UserServiceImpl中的增删改查方法
    Pointcut(切入点):目标对象中已经增强的方法,比如我们可以对增删改进行增强,这3个将作为切入点
    Advice(通知/增强):增强的代码,如invoke方法前后的代码
    Target(目标对象):被代理的对象,如上面UserServiceImpl
    Weaving(织入):把增强应用切入点的过程.
    Proxy(代理):将通知织入到目标对象后,形成代理对象
    Aspect(切面): 是切入点和通知的结合

    4 Spring AOP

    4.1 准备目标对象

    目标对象为上面UserServiceImpl对象

    4.2 准备通知

    创建通知类如下,处理不同类型通知

    public class MyAdvice {
        
        //前置通知  
    //      |-目标方法运行之前调用
        //后置通知(如果出现异常不会调用)
    //      |-在目标方法运行之后调用
        //环绕通知
    //      |-在目标方法之前和之后都调用
        //异常拦截通知
    //      |-如果出现异常,就会调用
        //后置通知(无论是否出现 异常都会调用)
    //      |-在目标方法运行之后调用
    //----------------------------------------------------------------
        //前置通知
        public void before(){
            System.out.println("这是前置通知!!");
        }
        //后置通知
        public void afterReturning(){
            System.out.println("这是后置通知(如果出现异常不会调用)!!");
        }
        //环绕通知
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            System.out.println("这是环绕通知之前的部分!!");
            Object proceed = pjp.proceed();//调用目标方法
            System.out.println("这是环绕通知之后的部分!!");
            return proceed;
        }
        //异常通知
        public void afterException(){
            System.out.println("出事啦!出现异常了!!");
        }
        //后置通知
        public void after(){
            System.out.println("这是后置通知(出现异常也会调用)!!");
        }
    }
    

    4.3 将通知织入目标对象

    配置application.xml,引入目标对象及通知对象的bean,

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
    
    <!-- 准备工作: 导入aop(约束)命名空间 -->
    <!-- 1.配置目标对象 -->
        <bean name="userService" class="cn.ibso.service.UserServiceImpl" ></bean>
    <!-- 2.配置通知对象 -->
        <bean name="myAdvice" class="cn.ibso.springaop.MyAdvice" ></bean>
    <!-- 3.配置将通知织入目标对象 -->
        <aop:config>
            <!-- 配置切入点  -->
            <aop:pointcut expression="execution(public void cn.itcast.service.UserServiceImpl.save())" id="pc"/>
            <aop:aspect ref="myAdvice" >
                <!-- 指定名为before方法作为前置通知 -->
                <aop:before method="before" pointcut-ref="pc" />
                <!-- 后置 -->
                <aop:after-returning method="afterReturning" pointcut-ref="pc" />
                <!-- 环绕通知 -->
                <aop:around method="around" pointcut-ref="pc" />
                <!-- 异常拦截通知 -->
                <aop:after-throwing method="afterException" pointcut-ref="pc"/>
                <!-- 后置 -->
                <aop:after method="after" pointcut-ref="pc"/>
            </aop:aspect>
        </aop:config>
    </beans>
    

    其中切入点的演化可以如下

                public void cn.ibso.service.UserServiceImpl.save() 
                void cn.ibso.service.UserServiceImpl.save()
                * cn.ibso.service.UserServiceImpl.save()
                * cn.ibso.service.UserServiceImpl.*()           
                * cn.ibso.service.*ServiceImpl.*(..)
                * cn.ibso.service..*ServiceImpl.*(..)
    

    编写测试代码

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:cn/itcast/d_springaop/applicationContext.xml")
    public class Demo {
        @Resource(name="userService")
        private UserService us;
        
        @Test
        public void fun1(){
            us.save();
        }
        
    }
    

    4.4 使用注解

    在applicationContext中开启注解

    <!-- 1.配置目标对象 -->
        <bean name="userService" class="cn.itcast.service.UserServiceImpl" ></bean>
    <!-- 2.配置通知对象 -->
        <bean name="myAdvice" class="cn.itcast.e_annotationaop.MyAdvice" ></bean>
    <!-- 3.开启使用注解完成织入 -->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    

    在通知类中以@Aspect表示通知类,

    @Aspect
    //表示该类是一个通知类
    public class MyAdvice {
        @Pointcut("execution(* cn.ibso.service.*ServiceImpl.*(..))")
        public void pc(){}
        //前置通知
        //指定该方法是前置通知,并制定切入点
        @Before("MyAdvice.pc()")
        public void before(){
            System.out.println("这是前置通知!!");
        }
        //后置通知
        @AfterReturning("execution(* cn.ibso.service.*ServiceImpl.*(..))")
        public void afterReturning(){
            System.out.println("这是后置通知(如果出现异常不会调用)!!");
        }
        //环绕通知
        @Around("execution(* cn.ibso.service.*ServiceImpl.*(..))")
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            System.out.println("这是环绕通知之前的部分!!");
            Object proceed = pjp.proceed();//调用目标方法
            System.out.println("这是环绕通知之后的部分!!");
            return proceed;
        }
        //异常通知
        @AfterThrowing("execution(* cn.ibso.service.*ServiceImpl.*(..))")
        public void afterException(){
            System.out.println("出事啦!出现异常了!!");
        }
        //后置通知
        @After("execution(* cn.ibso.service.*ServiceImpl.*(..))")
        public void after(){
            System.out.println("这是后置通知(出现异常也会调用)!!");
        }
    }
    

    相关文章

      网友评论

          本文标题:Spring 入门2

          本文链接:https://www.haomeiwen.com/subject/sctndftx.html