Spring的学习

新知识的领悟

由于贪玩太久没有发布博客了,好多知识都快忘了.
从今天开始每天都做个笔记记录自己的每一天
争取每天学一点知识。

1.1编写流程(基于xml)

2.编写目标类:dao和service
3.spring配置文件
IoC:
DI:
实例化方式:
默认构造
静态工厂:
实例工厂:
作用域:
生命周期:
后处理bean BeanPostProcessor接口, ,对容器中所有的bean都生效
属性注入
构造方法注入:
setter方法注入:
p命名空间:简化 注意声明命名空间
SpEL:

   #{123}  #{'abc'}
   #{beanId.propName?.methodName()}
   #{T(类).静态方法|字段}
集合
   数组<array>
   List <list>
   Set <set>
   Map <map><entry key="" value="">
   Properties <props><prop key="">....

IoC:

4.核心api
BeanFactory,延迟实例化bean,第一次调用getBean
ApplicationContext 一般常用,功能更强
ClassPathXmlApplicationContext 加载classpath xml文件
FileSystemXmlApplicationContext 加载指定盘符文件 , ServletContext.getRealPath()

1.3注解

1.扫描含有注解的类

2.常见的注解
@Component 组件,任意bean
WEB
@Controller web层
@Service service层
@Repository dao层
注入 –> 字段或setter方法
普通值:@Value
引用值:
类型:@Autowired
名称1:@Autowired @Qualifier(“名称”)
名称2:@Resource(“名称”)
作用域:@Scope(“prototype”)
生命周期:
初始化:@PostConstruct
销毁方法:@PreDestroy

1.4注解和xml混合使用

1.将所有的bean都配置xml中

2.将所有的依赖都使用注解
@Autowired
默认不生效。为了生效,需要在xml配置:

  • 总结:

    注解1:
    注解2:
    1.一般情况两个注解不一起使用。

    1. “注解1”扫描含有注解(@Component 等)类,注入注解自动生效。
      “注解2”只在xml和注解(注入)混合使用时,使注入注解生效。

2 AOP

  • 2.1AOP介绍
  • 2.1.1什么是AOP

    在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
    AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
    经典应用:事务管理、性能监视、安全检查、缓存 、日志等
    Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码
    AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入

2.1.2AOP实现原理

aop底层将采用代理机制进行实现。
接口 + 实现类 :spring采用 jdk 的动态代理Proxy。
实现类:spring 采用 cglib字节码增强。

2.1.3AOP术语【掌握】

  • 1.target:目标类,需要被代理的类。例如:UserService
  • 2.Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法
  • 3.PointCut 切入点:已经被增强的连接点。例如:addUser()
  • 4.advice 通知/增强,增强代码。例如:after、before
    1. Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程.
  • 6.proxy 代理类
    1. Aspect(切面): 是切入点pointcut和通知advice的结合
      一个线是一个特殊的面。
      一个切入点和一个通知,组成成一个特殊的面。

2.2手动方式

2.2.1JDK动态代理
JDK动态代理 对“装饰者”设计模式 简化。使用前提:必须有接口

  • 1.目标类:接口 + 实现类
  • 2.切面类:用于存通知 MyAspect
  • 3.工厂类:编写工厂生成代理
  • 4.测试
  • 2.2.1.1目标类

    public interface UserService {
        public void addUser();
        public void updateUser();
        public void deleteUser();
    }
    
  • 2.2.1.2切面类

    public class MyAspect {
        public void before(){
            System.out.println("鸡首");
            }    
        public void after(){
            System.out.println("牛后");
        }
    }
    
  • 2.2.1.3工厂

    public class MyBeanFactory {
    
        public static UserService createService(){
            //1 目标类
            final UserService userService = new UserServiceImpl();
            //2切面类
            final MyAspect myAspect = new MyAspect();
            /* 3 代理类:将目标类(切入点)和 切面类(通知) 结合 --> 切面
             *     Proxy.newProxyInstance
             *         参数1:loader ,类加载器,动态代理类 运行时创建,任何类都需要类加载器将其加载到内存。
             *             一般情况:当前类.class.getClassLoader();
             *                     目标类实例.getClass().get...
             *         参数2:Class[] interfaces 代理类需要实现的所有接口
             *             方式1:目标类实例.getClass().getInterfaces()  ;注意:只能获得自己接口,不能获得父元素接口
             *             方式2:new Class[]{UserService.class}   
             *             例如:jdbc 驱动  --> DriverManager  获得接口 Connection
             *         参数3:InvocationHandler  处理类,接口,必须进行实现类,一般采用匿名内部
             *             提供 invoke 方法,代理类的每一个方法执行时,都将调用一次invoke
             *                 参数31:Object proxy :代理对象
             *                 参数32:Method method : 代理对象当前执行的方法的描述对象(反射)
             *                     执行方法名:method.getName()
             *                     执行方法:method.invoke(对象,实际参数)
             *                 参数33:Object[] args :方法实际参数
             * 
             */
            UserService proxService = (UserService)Proxy.newProxyInstance(
                                    MyBeanFactory.class.getClassLoader(), 
                                    userService.getClass().getInterfaces(), 
                                    new InvocationHandler() {
    
                                        @Override
                                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
                                            //前执行
                                            myAspect.before();
    
                                            //执行目标类的方法
                                            Object obj = method.invoke(userService, args);
    
                                            //后执行
                                            myAspect.after();
    
                                            return obj;
                                        }
                                    });
    
            return proxService;
        }
    
    }
    
  • 2.2.1.4测试
    @Test
    public void demo01(){
        serService userService = MyBeanFactory.createService();
        userService.addUser();
        userService.updateUser();
        userService.deleteUser();
    }
    

2.3AOP联盟通知类型

AOP联盟为通知Advice定义了org.aopalliance.aop.Advice
Spring按照通知Advice在目标类方法的连接点位置,可以分为5类

  • 前置通知 org.springframework.aop.MethodBeforeAdvice
  • 在目标方法执行前实施增强
  • 后置通知 org.springframework.aop.AfterReturningAdvice
  • 在目标方法执行后实施增强
  • 环绕通知 org.aopalliance.intercept.MethodInterceptor
  • 在目标方法执行前后实施增强
  • 异常抛出通知 org.springframework.aop.ThrowsAdvice
  • 在方法抛出异常后实施增强
  • 引介通知 org.springframework.aop.IntroductionInterceptor
  • 在目标类中添加一些新的方法和属性
环绕通知,必须手动执行目标方法
try{
   //前置通知
   //执行目标方法
   //后置通知
} catch(){
   //抛出异常通知
}

3AspectJ

  • 3.1介绍

    AspectJ是一个基于Java语言的AOP框架
    Spring2.0以后新增了对AspectJ切点表达式支持
    @AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面
    新版本Spring框架,建议使用AspectJ方式来开发AOP
    主要用途:自定义开发

  • 3.2切入点表达式【掌握】

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

  • 综合2
  • 2.within:匹配包或子包中的方法(了解)
    within(com.itheima.aop..*)
  • 3.this:匹配实现接口的代理对象中的方法(了解)
    this(com.itheima.aop.user.UserDAO)
  • 4.target:匹配实现接口的目标对象中的方法(了解)
    target(com.itheima.aop.user.UserDAO)
  • 5.args:匹配参数格式符合标准的方法(了解)
    args(int,int)
  • 6.bean(id) 对指定的bean所有的方法(了解)
    bean(‘userServiceId’)

3.3AspectJ 通知类型

aop联盟定义通知类型,具有特性接口,必须实现,从而确定方法名称。
aspectj 通知类型,只定义类型名称。已经方法格式。
个数:6种,知道5种,掌握1中。

  • before:前置通知(应用:各种校验)
    在方法执行前执行,如果通知抛出异常,阻止方法运行
  • afterReturning:后置通知(应用:常规数据处理)
    方法正常返回后执行,如果方法中抛出异常,通知无法执行
    必须在方法执行后才执行,所以可以获得方法的返回值。
  • around:环绕通知(应用:十分强大,可以做任何事情)
    方法执行前后分别执行,可以阻止方法的执行
    必须手动执行目标方法
  • afterThrowing:抛出异常通知(应用:包装异常信息)
    方法抛出异常后执行,如果方法没有抛出异常,无法执行
  • after:最终通知(应用:清理现场)
    方法执行完毕后执行,无论方法中是否出现异常
    环绕
try{
     //前置:before
    //手动执行目标方法
    //后置:afterRetruning
} catch(){
    //抛出异常 afterThrowing
} finally{
    //最终 after
}