我是如何学习Spring的(二)

简介

MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。
Spring是典型的控制层的框架,Model层有Hibernate、Mybatis等框架可选,View有Struts2、Spring MVC可供选择,然而Spring处于无法被替换控制层。

AOP

Aspect Oriented Programming(面向切面编程) 是继面向对象编程后的又一伟大创造。面向切面编程可以理解为程序的运行被切成了几段,每一段都加上不同的功能,加权限,加日志等等,AOP的核心是动态代理。

AOP的术语:

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

  • beans.xml配置文件

    1
    2
    3
    4
    5
    6
    //Spring中配置bean的基本方法(IOC构造方法实例化)
    <bean id="u" class="com.spring.dao.impl.UserDaoImpl"></bean>
    //将userDao注入到userService()中
    <bean id="userService" class="com.spring.service.UserService">
    <property name="userDao" ref="u"></property>
    </bean>
  • 代理(proxy)类的实现,在method方法执行前,增加一个功能,beforeMethod()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    public class LogInterceptor implements InvocationHandler, org.springframework.cglib.proxy.InvocationHandler{

    private Object target; //定义代理对象

    public void beforeMethod(Method m){
    System.out.println(m.getName()+" start"); //在被代理对象执行前,先执行该方法
    }

    public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable {

    beforeMethod(method);
    method.invoke(target, args);
    return null;
    }
    }
  • 普通Dao对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    public interface UserDao {

    public void save(User u);
    public void delete();
    }

    public class UserDaoImpl implements UserDao{

    public void save(User u) {

    System.out.println("add user!");
    }

    public void delete() {

    System.out.println("delete user!");
    }
    }
  • 被代理的Service类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class UserService {

    private UserDao userDao;

    public void add(User user){
    userDao.save(user);
    }

    public UserDao getUserDao() {
    return userDao;
    }

    public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
    }
    }
  • 测试类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class UserServiceTest {

    @Test
    public void testAdd(){
    BeanFactory applicationContext = new ClassPathXmlApplicationContext("beans.xml");
    UserService userService = (UserService) applicationContext.getBean("userService");

    User user= new User();
    user.setUserName("jessyon");
    user.setPassword("12346");
    userService.add(user);
    }
    @Test
    public void testProxy(){
    UserDao userDao= new UserDaoImpl();
    LogInterceptor li = new LogInterceptor();
    li.setTarget(userDao);
    UserDao userDaoProxy=(UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), new Class[]{UserDao.class}, li);
    userDaoProxy.save(new User());
    userDaoProxy.delete();
    }
    }
  • 执行结果

    1
    2
    3
    4
    5
    在每个方法执行前,都先执行了代理后,新增的方法
    save start
    add user!
    delete start
    delete user!
  • 注:BeanFactory和ApplicationContext的区别

  • ApplicationContext类继承了BeanFactory.
  • BeanFactory在使用到这个类的时候,getBean()方法的时候才会加载这个类.
  • ApplicationContext类加载配置文件的时候,创建所有的类.
  • ApplicationContext对BeanFactory提供了扩展:
    国际化处理
    事件传递
    Bean自动装配
    各种不同应用层的Context实现