Spring第二阶段

Spring

Spring的Bean的管理注解开发

xml:结构清晰
注解:开发方便(属性注入)

Spring的IOC注解基础

  1. 引包(Spring-aop的包),Spring4.x版本需要引,低的版本不用引了,都内置了
  2. 引入约束,在spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html 中找到context的约束。
  3. 要想设置离线提示信息,则要在window中的属性设置一下,约束文件设置context的约束文件
  4. 开启组件扫描 <context:component-scan base-package="包路劲注意不要到类"></component>
  5. 加注解:在类上加 @Component("userDao")
  6. 要想用属性,可以在实体类中添加一个私有的属性注解直接加在属性上就行@Value(" ") ,如果有set方法则需要加在set方法上。

Spring的IOC的注解详情

  • 定义Bean的注解:

    • @Component:修饰类,相当于<bean id="">
      • Spring 中提供了三个衍生注解:
        • @Controller : 修饰web层类的
        • @Service : 修饰业务层类的
        • @Repository : 修饰DAO层类的
  • 属性注入的注解:

    • @Value :注入普通类型的值
    • @Autowired :对象类型的属性注入,但是默认是按类型注入的,不是按名称注入
      • 要想按名称去注入,可以使用@Qulifer(value=””)的注解与@Autowired一起使用
      • 还有一个Resource :相当于@Qulifer(value=””)的注解与@Autowired一起使用的效果,此注解不是Spring包中的
  • Bean的作用范围的注解:

    • @Scope(“ “) :控制Bean的作用范围,默认是单例的,里面的属性跟xml里的一样。
  • Bean的生命周期的注解:(在要运行的方法上)

    • PostConstruct:初始化注解
    • PreDestory:销毁注解

Spring的AOP

什么是AOP

AOP最初是AOP联盟开发出来的,Spring用的人家的。

AOP(Aspect Oriented Programming) :面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

AOP:面向切面编程,是OOP(面向对象编程)扩展和延伸,解决OOP中一些问题而出现。传统方式使用是纵向继承体系,AOP采用叫做横向抽取机制取代传统方式纵向继承机制对程序扩展和延伸

为什莫学习AOP

可以不修改源代码,对程序进行扩展。
主流应用:权限校验,日志记录,事务管理,性能检测。

AOP的底层实现原理(代理机制)

Spring底层实现AOP的原理:

  • JDK动态代理 :对实现了接口的类才可以产生代理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class JdkProxy {
    
    private UserDao userDao;
    public JdkProxy(UserDao userDao) {
        this.userDao = userDao;
    }
    public UserDao createProxy(){
        UserDao proxy = (UserDao)Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), new InvocationHandler() {
            
            @Override
            public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
                if(method.getName().equals("save")){
                    System.out.println("权限校验===========");
                    return method.invoke(userDao, args);
                }
                return method.invoke(userDao, args);
            }
        });
        return proxy;
    }
}
  • Cglib动态代理:对没有实现接口的类产生代理。底层字节码增强,产生子类对象。
    使用的时候直接把Spring的包引进来就行,因为,他里边已经集合了Cglib的包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//这里边实现MethodInterceptor的意思是实现回掉函数,下边的intercept就相当于JDK代理中的invoke方法。所以增强方法中的setCallback中传入一个this即可
public class CglibProxy implements MethodInterceptor{
    private ProductDao productDao;
    public CglibProxy(ProductDao productDao){
        this.productDao = productDao;
    }
    public ProductDao createProxy(){
        // 创建Cglib的产生代理核心类:
        Enhancer enhancer = new Enhancer();
        // 设置父类:
        enhancer.setSuperclass(productDao.getClass());
        // 设置回调:类似InvocationHandler
        enhancer.setCallback(this);
        // 产生代理:
        ProductDao proxy = (ProductDao) enhancer.create();
        return proxy;
    }
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        if(method.getName().equals("save")){
            System.out.println("权限校验=========");
            return methodProxy.invokeSuper(proxy, args);
        }
        return methodProxy.invokeSuper(proxy, args);
    }
}

SpringAOP中的相关的术语

  1. JoinPoint:连接点,可以被拦截(增强)到的点。
  2. Pointcut:切入点,真实被拦截到的点。
  3. Advice: 通知/增强,增强的代码的实现。
    • 权限校验代码/日志记录 的这种代码称为是通知,增强
  4. Introduction:引介,增强的一种。类层面的增强。(一般不用)
  5. Target:目标,被增强的类(UserDao)
  6. Weaving:织入,将Advice应用到Target的过程。
  7. Proxy:被增强织入以后产生的代理类
  8. Aspect:切面,切面指的是多个切入点和多个通知的组合。

SpringAOP的入门

  1. 引入jar包 spring-aop-4.2.4.RESEASE.jar
    • 还有依赖包中aop的联盟的包com.springsource.org.aopalliance
    • 因为Spring用的AOP中aspectj的技术,所以还得引一个他们的依赖包:com.springsource.org.aspectj.weaver
    • 还有一个Spring整合aspectj的包(在lib中):sprin g-aspects
  2. 编写接口跟实现类
  3. 创建一个Spring的配置文件,约束引入AOP的部分
1
2
3
4
5
 <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">
  1. 将类配置到Spring中
1
2
3
4
 <bean id="customerDao" class="com.aop.demo3.CustomerDaoImpl">
</bean>
<bean id="myAspectXml" class="" />
  • 编写一个切类面
1
2
3
4
5
public class MyAspectXml{
    public void checkPrivilege(){
        syso("权限校验------");
    }
}
  • 配置切面类
1
2
3
4
5
6
7
8
9
10
  //配置Spring的AOP
   <!-- 配置Spring的AOP -->
   <aop:config>
       <!-- 切入点: -->
       <aop:pointcut expression="execution(* com.itheima.aop.demo3.CustomerDaoImpl.save(..))" id="pointcut1"/>
       <!-- 配置切面 -->
       <aop:aspect ref="myAspectXml">
           <aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
       </aop:aspect>
   </aop:config>

Spring的AOP的切入点的表达式写法

  • 语法:很灵活,随便写
    • [访问修饰符] 方法的返回值 类名.方法名(参数)
      • 举例: * 表示任意类,任意返回值,任意方法
1
2
3
4
   public void com.aop.demo.CustomerDaoImpl.save(..); //save()跟save(..)效果是一样的
   * *.*.demo.*DaoImpl.save(..);
   * com.aop.demo.CustomerDao+.save(..); // +表示它的实现类
   * com.aop.demo..*DaoImpl.save(..);   //表示任意包下的

Spring的AOP的通知的类型

  • 前置通知(before) : 在方法执行之前进行增强,可以获得切入点的信息

获得切入点的信息,传一个joinPoint对象进去

1
2
3
public void before(JoinPoint joinPoint){
   syso(前置通知=====joinPoint);
}

  • 后置通知(after-returning) :在方法执行之后进行增强,获取方法的返回值。

获得返回值:在配置文件标签上加一个resulting="result名字随便起"
然后再在增强的类中加一个

1
2
3
public void before(Object result){
   syso(后置通知=====result);
}

  • 环绕通知(around) :在方法执行之前跟执行之后进行增强,阻止目标方法的执行

//要想执行原有的目标方法要加一个ProceedingJoinPoint,因为增强的方法不知道是否有返回值所以一般会返回一个Object

1
2
3
4
5
6
public Object around(ProceedingJoinPoint joinPoint){
   syso("通知前");
   Object obj = joinPoint.proceed();
   syso("通知后");
   return obj;
}
  • 异常抛出通知(afterThrowing):在方法执行出现异常的时候进行增强,获取异常的信息。
    异常抛出之后后面的就不执行了,因为是运行时异常

可以获得异常的信息:在标签上加一个属性throwing="result任意起名"

1
2
3
public void around(Throwable e){
   syso("异常抛出通知---"+e.getMessage());
}

  • 最终通知(after):类似try,catch中的finally。无论方法是否成功都会执行.

  • 引介通知(不关注)


如果一个类实现了接口,则Spring用JDK代理,如果不加接口就默认用Cglib动态代理实现。当然都不能加final,都要产生子类的

Spring与Junit的整合

  • 引入test包spring-test(lib包中),当然环境下有JUnit

  • 然后再在测试类上加两个注解

    1
    2
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml") //全名
  • 下边想用哪个类直接注入即可用

    1
    2
    @Resource(name="customerDao")
    private CustomerDao customerDao;
  • 然后下边的Test单元测试中直接用customerDao即可,不用再加载配置文件那么麻烦

    • 注:这里是只有是Spring跟JUnit整合的时候才能用,因为他里面已经做了一些操作,要想在别的地方使用注解的话,就必须要导包加扫描了

扩展XML和注解整合开发

  • xml:管理类
  • 注解:属性注入
  1. 把service跟Dao都在配置文件中实例化了
  2. 不要开扫描否则会出错因为扫描会扫描类上的注解文件,但是类上面没有只有属性上有,所以开启<context:annotation-config />即可, 支持@Resource,@Value,@Autowared等属性上的注解
1
2
@Resource(name="UserDao")
private UserDao userDao;
张冲 wechat
欢迎扫一扫上面的微信关注我,一起交流!
坚持原创技术分享,您的支持将鼓励我继续创,点击打赏!