[Spring系列02]Spring AOP模拟

在博文[Spring系列01]Spring IOC/DI模拟中简略模拟了Spring IOC/DI的实现原理,本文接着模拟了Spring AOP的实现原理。

代码结构图如下:

全部代码如下:

UserDAO.java

package com.ctsh.dao;
import com.ctsh.model.User;

public interface UserDAO {
    public void save(User user);
    public void delete();
}

UserDAO

UserDAOImpl.java

package com.ctsh.dao.impl;

import com.ctsh.dao.UserDAO;
import com.ctsh.model.User;

public class UserDAOImpl implements UserDAO {

    public void save(User user) {

        //Hibernate
        //JDBC
        //XML
        //NetWork
        System.out.println("user saved!");
    }

    public void delete() {
        System.out.println("user deteleted");

    }

}

UserDAOImpl

User.java

package com.ctsh.model;

public class User {
    private String username;
    private String password;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

User

UserService.java

package com.ctsh.service;

import com.ctsh.dao.UserDAO;
import com.ctsh.model.User;

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;
    }
}

UserService

BeanFactory.java

package com.ctsh.spring;

public interface BeanFactory {
    public Object getBean(String id);
}

BeanFactory

ClassPathXmlApplicationContext.java

package com.ctsh.spring;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;

public class ClassPathXmlApplicationContext implements BeanFactory {

    private Map<String, Object> beans = new HashMap<String, Object>();

    // IOC Inverse of Control DI Dependency Injection
    public ClassPathXmlApplicationContext() throws Exception {
        SAXBuilder sb = new SAXBuilder();

        Document doc = sb.build(this.getClass().getClassLoader()
                .getResourceAsStream("beans.xml"));
        Element root = doc.getRootElement();
        List list = root.getChildren("bean");
        for (int i = 0; i < list.size(); i++) {
            Element element = (Element) list.get(i);
            String id = element.getAttributeValue("id");
            String clazz = element.getAttributeValue("class");
            Object o = Class.forName(clazz).newInstance();
            System.out.println(id);
            System.out.println(clazz);
            beans.put(id, o);

            for (Element propertyElement : (List<Element>) element
                    .getChildren("property")) {
                String name = propertyElement.getAttributeValue("name"); // userDAO
                String bean = propertyElement.getAttributeValue("bean"); // u
                Object beanObject = beans.get(bean);// UserDAOImpl instance

                String methodName = "set" + name.substring(0, 1).toUpperCase()
                        + name.substring(1);
                System.out.println("method name = " + methodName);

                Method m = o.getClass().getMethod(methodName,
                        beanObject.getClass().getInterfaces()[0]);
                m.invoke(o, beanObject);
            }

        }

    }

    public Object getBean(String id) {
        return beans.get(id);
    }

}

beans.xml

<beans>
    <bean id="u" class="com.ctsh.dao.impl.UserDAOImpl">

    </bean>
    <bean id="userService" class="com.ctsh.service.UserService">
        <property name="userDAO" bean="u" />
    </bean>

</beans>

beans

LogInterceptor.java

package com.ctsh.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class LogInterceptor implements InvocationHandler {
    private Object target;

    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }

    public void beforeMethod(Method m) {

        System.out.println(m.getName() + " start");
    }

    public Object invoke(Object proxy, Method m, Object[] args)
            throws Throwable {
        beforeMethod(m);
        m.invoke(target, args);
        return null;
    }
}

LogInterceptor

测试类UserServiceTest.java

package com.ctsh.service;
import java.lang.reflect.Proxy;

import org.junit.Test;

import com.ctsh.aop.LogInterceptor;
import com.ctsh.dao.UserDAO;
import com.ctsh.dao.impl.UserDAOImpl;
import com.ctsh.model.User;
import com.ctsh.service.UserService;
import com.ctsh.spring.BeanFactory;
import com.ctsh.spring.ClassPathXmlApplicationContext;

public class UserServiceTest {

    @Test
    public void testAdd() throws Exception {
        BeanFactory applicationContext = new ClassPathXmlApplicationContext();
        UserService service = (UserService)applicationContext.getBean("userService");
        User u = new User();
        u.setUsername("zhangsan");
        u.setPassword("zhangsan");
        service.add(u);
    }

    @Test
    public void testProxy() {
        UserDAO userDAO = new UserDAOImpl();
        LogInterceptor li = new LogInterceptor();
        li.setTarget(userDAO);
        UserDAO userDAOProxy = (UserDAO)Proxy.newProxyInstance(userDAO.getClass().getClassLoader(), userDAO.getClass().getInterfaces(), li);
        System.out.println(userDAOProxy.getClass());
        userDAOProxy.delete();
        userDAOProxy.save(new User());

    }
}

UserServiceTest

由运行结果可知,在调用对象userDAOProxy的delete()方法和save()方法的时候均输出了日志。

由代码可知,AOP的实现也主要是通过java的代理反射机制实现的,不过值得一提的是,Spring中代理的实现方式还可以通过CGLIB实现。

时间: 2024-10-25 14:22:06

[Spring系列02]Spring AOP模拟的相关文章

[Spring系列01]Spring IOC/DI模拟

本文以一个简单的实例大致模拟Spring IOC/DI的运行原理,代码简单分dao,model,service三层.即:dao 与数据库的操作,增删改查等方法model 一般都是javabean对象,例如与数据库的某个表相关联.service 供外部调用,等于对dao,model等进行了包装. 程序结构图如下: 先粘贴部分代码,再进行解释: UserDAO.java package com.ctsh.dao; import com.ctsh.model.User; public interfac

【Spring系列】Spring AOP面向切面编程

前言 接上一篇文章,在上午中使用了切面做防重复控制,本文着重介绍切面AOP. 在开发中,有一些功能行为是通用的,比如.日志管理.安全和事务,它们有一个共同点就是分布于应用中的多处,这种功能被称为横切关注点(cross-cutting concerns). DI(依赖注入)有助于应用对象之间的解耦,而AOP可以实现横切关注点与他们所影响的对象之间的解耦. 面向切面编程在Spring AOP中有4种类型的调用,方法调用的之前.后.异常增加其他方法,方法调用的前和后调用其他方法,将方法中的参数传递给其

Spring系列之Spring常用注解总结

传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.事物,这么做有两个缺点:1.如果所有的内容都配置在.xml文件中,那么.xml文件将会十分庞大:如果按需求分开.xml文件,那么.xml文件又会非常多.总之这将导致配置文件的可读性与可维护性变得很低.2.在开发中在.java文件和.xml文件之间不断切换,是一件麻烦的事,同时这种思维上的不连贯也会降低开发的效率.为了解决这两个问题,Spring引入了注解,通过"@XXX"的方式,让注解与Java Bean紧密

Spring系列之——Spring事务以及两大核心IOC和AOP

1 Spring事务 1.1 Spring事务是什么(百度) 事务是对一系列的数据库操作(比如插入多条数据)进行统一的提交或是回滚操作,如果插入成功,那么一起成功,如果中间一条出现异常,那么回滚之前的所有操作. Spring事务管理机制使用的是TransactionManager进行管理.回滚注解@Transactional. 2 Spring特征 1)开源框架. 2)IOC(控制反转) 将类的创建和依赖关系写在配置文件中,由配置文件注入,实现松耦合. 3)AOP 将安全.事务等程序逻辑相对独立

Spring系列之:AOP

一,相关名词 切面(Aspect):一个横切功能的模块化,这个功能可能会横切多个对象(业务),比如:aMethod()方法就是一个"切面",它横切到多个业务中 切入点(Pointcut):可以插入 "横切逻辑(如aMethod())"的方法.比如:"调用add()"就是一个切点. 通知: 前置通知(Before Advice):在切入点add()方法执行之前,插入的通知. 后置通知(After Returning Advice):在切入点add(

Spring系列之——spring security

1 搭建springboot 2 配置pom依赖(springboot版本为2.1.3) <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> 3 写一个controller类 4 SpringBootApplication中增加注解Comp

Spring基础系列12 -- Spring AOP AspectJ

Spring基础系列12 -- Spring AOP AspectJ 转载:http://www.cnblogs.com/leiOOlei/p/3613352.html 本文讲述使用AspectJ框架实现Spring AOP. 再重复一下Spring AOP中的三个概念, Advice:向程序内部注入的代码. Pointcut:注入Advice的位置,切入点,一般为某方法. Advisor:Advice和Pointcut的结合单元,以便将Advice和Pointcut分开实现灵活配置. Aspe

Spring基础系列9 -- Spring AOP

Spring基础系列9 -- Spring AOP 转载:http://www.cnblogs.com/leiOOlei/p/3556054.html Spring AOP即Aspect-oriented programming,面向切面编程,是作为面向对象编程的一种补充,专门用于处理系统中分布于各个模块(不同方法)中的交叉关注点的问题.简单地说,就是一个拦截器(interceptor)拦截一些处理过程.例如,当一个method被执行,Spring AOP能够劫持正在运行的method,在met

Spring系列之AOP的原理及手动实现

目录 Spring系列之IOC的原理及手动实现 Spring系列之DI的原理及手动实现 引入 到目前为止,我们已经完成了简易的IOC和DI的功能,虽然相比如Spring来说肯定是非常简陋的,但是毕竟我们是为了理解原理的,也没必要一定要做一个和Spring一样的东西.到了现在并不能让我们松一口气,前面的IOC和DI都还算比较简单,这里要介绍的AOP难度就稍微要大一点了. tips 本篇内容难度较大,每一步都需要理清思路,可能需要多看几遍,多画类图和手动实现更容易掌握. AOP 什么是AOP Asp