spring03

Aop的底层原理

spring03_第1张图片

 

 

 

JDK动态代理

要求写的类实现了接口的时候
被代理类和代理类是兄弟关系,都实现了相同接口
获取容器中代理类对象的两种方式
1接口的字节码
2代理类对象的id对象(被代理类简类名首字母小写)

 

 spring03_第2张图片

 

 spring03_第3张图片

 

 

 

CGLIB代理

要求写的类实现了接口的时候
被代理类和代理类是兄弟关系,都实现了相同接口
获取容器中代理类对象的两种方式
1被代理类的字节码
2代理类对象的id对象(被代理类简类名首字母小写)

 

 spring03_第4张图片

 

 spring03_第5张图片

 

 动态代理和静态代理

静态代理(JDK静态)
只能代理某一个接口的实现类 

//支付接口
public interface Pay {
    void payMoney(double money);
}
//真实用户
public class Customer implements Pay{

    @Override
    public void payMoney(double money) {
        System.out.println("客人支付了"+money+"元");
    }

}
//Alipay:代理,而且是在不改变真实用户代码的基础之上对真实用户功能的拓展
public class Alipay implements Pay{
    private Pay pay;
    
    public Alipay(Pay pay) {
        this.pay = pay;
    }

    @Override
    public void payMoney(double money) {
        System.out.println("支付宝代替帮忙把钱取出来");
        this.pay.payMoney(money);
        System.out.println("支付宝代替把钱打给商家");
    }

}
  @Test
    public void test01() {
        Customer customer = new Customer();
        Alipay apl = new Alipay(customer);
        apl.payMoney(50);
    }
输出:
支付宝代替帮忙把钱取出来
客人支付了50.0元
支付宝代替把钱打给商家

动态代理(JDK动态)
可以代理任意接口的实现类

方式一:

public class InvocationHandlerImp implements InvocationHandler{
    //需要代理的目标对象
    private Object obj;
    public InvocationHandlerImp(Object obj) {
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("动态代理把钱从银行取出来");
//        proxy:  - 指代我们所代理的那个真实对象
//        method: - 指代的是我们所要调用真实对象的某个方法的Method对象
//        args:  - 指代的是调用真实对象某个方法时接受的参数
        Object invoke = method.invoke(obj, args);
        System.out.println("动态代理把钱打给商家");
        return invoke;
    }

}
@Test
    public void test02() {
        Customer customer = new Customer();
        InvocationHandlerImp ih = new InvocationHandlerImp(customer);
//        loader:      一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
//        interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
//        h:           一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
        //方法返回的是代理类对象
        Pay ali = (Pay)Proxy.newProxyInstance(customer.getClass().getClassLoader(), customer.getClass().getInterfaces(),ih);
        ali.payMoney(45.2);
    }
输出:
动态代理把钱从银行取出来
客人支付了45.2元
动态代理把钱打给商家

方式二:

public class InvocationHandlerImp2 implements InvocationHandler{
    private Object obj;
    
    public Object getObj(Object obj) {
        this.obj=obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("第二种动态代理把钱从银行取出来");
        Object invoke = method.invoke(obj, args);
        System.out.println("第二种动态代理把钱打给商家");
        return invoke;
    }

}
@Test
    public void test03() {
        InvocationHandlerImp2 ith = new InvocationHandlerImp2();
        Pay ali = (Pay)ith.getObj(new Customer());
        ali.payMoney(99);
    }
输出:
第二种动态代理把钱从银行取出来
客人支付了99.0元
第二种动态代理把钱打给商家

静态代理和动态代理的区别

相同点:
1.都是在不改变被代理类代码的基础上对被代理类的功能进行拓展
2.都实现了接口
不同点:
静态代理只能代理某个接口的实现类,动态可以代理任意接口的实现类

  切面的五种通知

前置通知[@Before]:在目标方法执行之前执行
后置通知[@After]:无论目标方法有没有执行成功,后置通知都会执行。
返回通知[@AfterReturning]:只有在目标方法执行成功的情况下,返回通知才会执行
异常通知[@AfterThrowing]:只有在目标方法出现异常的情况下,异常通知才会执行。
环绕通知[@Around]:以一敌四。

基于注解配置的Aop

具体步骤:

1.在applicationContext.xml文件中配置

package="com.offcn">
    

2.定义一个接口

public interface Caculator {
    public int add(int i,int j);
    public int jian(int i,int j);
    public int cheng(int i,int j);
    public int div(int i,int j);
}

3.定义一个接口的实现类,重写接口的方法

@Component
public class CaculatorImp implements Caculator{
    //方法签名:包名+类名+方法名+参数列表
    @Override
    public int add(int i, int j) {
        int result = i+j;
        System.out.println("目标方法执行了");
        //int z = i/0;
        return result;
    }

4.定义一个切面类,对接口的实现类进行扩展

@Component
@Aspect
public class LogAspect {
    //切入点【PointCut】:指定对谁进行拓展【本质:表达式】
    @Pointcut(value="execution(public int com.offcn.bean.CaculatorImp.*(..))")
    public void pointCut() {}
    //切入点表达式,引入切入点
    @Before(value="pointCut()")
    //连接点【JoinPoint】:通知 和 目标方法的交点,称之为:连接点
    public void beforeLog(JoinPoint joinPoint) {
        //com.offcn.bean.CaculatorImp.add(int, int)
        Signature signature = joinPoint.getSignature();
        //方法名add
        String name = signature.getName();
        //传递给目标方法的参数值信息
        Object[] args = joinPoint.getArgs();
        System.out.println("日志切面前置通知...执行的目标方法为"+name+"传递给目标方法的参数值为"+Arrays.toString(args));
    }
    @After(value="pointCut()")
    public void afterLog() {
        System.out.println("日志切面后置通知...");
    }
    //返回通知:获取目标方向的返回值信息,要求返回通知的参数名和@AfterReturning属性值保持一致,返回通知的参数类型用Object类型
    @AfterReturning(value="pointCut()",returning = "result")
    public void afterReturningLog(Object result) {
        System.out.println("日志切面返回通知...目标方法的返回结果为"+result);
    }
    @AfterThrowing(value="pointCut()")
    public void afterThrowingLog() {
        System.out.println("日志切面异常通知...");
    }
}
@Test
    public void test01() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Caculator bean = (Caculator)context.getBean(Caculator.class);    
        bean.add(3, 4);
    }
 
 
输出:
日志切面前置通知...执行的目标方法为add传递给目标方法的参数值为[3, 4]
目标方法执行了
日志切面后置通知...
日志切面返回通知...目标方法的返回结果为7

5.定义一个事务切面类

@Component
@Aspect
public class TransactionAspect {
    //环绕通知的方法必须返回Object类型的参数
    @Around(value="com.offcn.bean.LogAspect.pointCut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) {
        Object proceed=null;
        try {
            try {
                //前置通知,开启事务
                System.out.println("事物切面=======开启事务");
                //实际调用了目标方法
                proceed = proceedingJoinPoint.proceed();
            }finally {
                //后置通知
            }
            //返回通知
            System.out.println("事物切面=======提交事务");
        }catch(Throwable e) {
            //异常通知
            System.out.println("事物切面=======y回滚事务");
        }
        return proceed;
    }
}
@Test
    public void test01() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Caculator bean = (Caculator)context.getBean(Caculator.class);    
        bean.add(3, 4);
    }
 
 
输出:
日志切面前置通知...执行的目标方法为add传递给目标方法的参数值为[3, 4]
事物切面=======开启事务
目标方法执行了
事物切面=======提交事务
日志切面后置通知...
日志切面返回通知...目标方法的返回结果为7

基于xml配置的Aop

class="com.offcn.bean.CaculatorImp">
    class="com.offcn.bean.LogAspect">
    class="com.offcn.bean.TransactionAspect">
    
        
        
            
            
            
            
        
        
            
        
    
输出:
事物切面=======开启事务
日志切面前置通知...执行的目标方法为add传递给目标方法的参数值为[3, 4]
目标方法执行了
日志切面后置通知...
日志切面返回通知...目标方法的返回结果为7
事物切面=======提交事务

Spring的JdbcTemplate

1.导包

2.在applicationContext.xml文件中配置JdbcTemplate对象

package="com.offcn">
    
    
    class="com.mchange.v2.c3p0.ComboPooledDataSource">
        
        
        
        
    
       
       class="org.springframework.jdbc.core.JdbcTemplate">
           
       

3.写实体类

4Dao层使用JdbcTemplate完成对数据表的操作

@Repository
public class EmployeeDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    //增加操作
    public void insert(Employee emp) {
        String sql="insert into employee(emp_name,salary) values(?,?)";
        jdbcTemplate.update(sql, emp.getEmp_name(),emp.getSalary());
    }
    //删除操作
    public void delete(int emp_id) {
        String sql="delete from employee where emp_id=?";
        jdbcTemplate.update(sql, emp_id);
    }
    //修改
    public void update(Employee emp) {
        String sql="update employee set emp_name=?,salary=? where emp_id=?";
        jdbcTemplate.update(sql, emp.getEmp_name(),emp.getSalary(),emp.getEmp_id());
    }
    //批量增删改
    public void insertList() {
        String sql="insert into employee(emp_name,salary) values(?,?)";
        List list = new ArrayList();
        list.add(new Object[] {"小李",3432.3});
        list.add(new Object[] {"小王",989.3});
        jdbcTemplate.batchUpdate(sql, list);
    }
    //查询单个对象
    public Employee selectById(int emp_id) {
        String sql = "select * from employee where emp_id=?";
        return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper(Employee.class), emp_id);
    }
    //查询单值
    public double maxSalary() {
        String sql = "SELECT MAX(salary) FROM employee";
        return jdbcTemplate.queryForObject(sql, Double.class);
    }
    //查询对象列表
    public List selectAll(){
        String sql = "select * from employee";
        return jdbcTemplate.query(sql, new BeanPropertyRowMapper(Employee.class));
    }
}

5.测试

@Test
    public void test01() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        EmployeeDao employeeDao = context.getBean(EmployeeDao.class);
        //Employee emp = new Employee("校长", 45434);
        //1添加
        //employeeDao.insert(emp);
        //2删除
        //employeeDao.delete(7);
        //3修改
        //Employee emp = new Employee(1, "乐乐", 7876.99);
        //employeeDao.update(emp);
        //4批量增加
        //employeeDao.insertList();
        //5查询单个对象
        //Employee employee = employeeDao.selectById(2);
        //System.out.println(employee);
        //6查询单值
        //double maxSalary = employeeDao.maxSalary();
        //System.out.println(maxSalary);
        //7查询对象列表
        List list = employeeDao.selectAll();
        for (Employee employee : list) {
            System.out.println(employee);
        }
    }

你可能感兴趣的:(spring03)