spring03随堂笔记
作者:互联网
Aop的底层原理
JDK动态代理
要求写的类实现了接口的时候 被代理类和代理类是兄弟关系,都实现了相同接口 获取容器中代理类对象的两种方式 1接口的字节码 2代理类对象的id对象(被代理类简类名首字母小写)
CGLIB代理
要求写的类实现了接口的时候 被代理类和代理类是兄弟关系,都实现了相同接口 获取容器中代理类对象的两种方式 1被代理类的字节码 2代理类对象的id对象(被代理类简类名首字母小写)
动态代理和静态代理
静态代理(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文件中配置
<context:component-scan base-package="com.offcn"></context:component-scan> <!-- 开启基于注解的切面支持 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
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
<bean id="caculator" class="com.offcn.bean.CaculatorImp"></bean> <bean id="logAspect" class="com.offcn.bean.LogAspect"></bean> <bean id="transactionAspect" class="com.offcn.bean.TransactionAspect"></bean> <aop:config> <aop:pointcut expression="execution(public int com.offcn.bean.CaculatorImp.*(..))" id="pointCut"/> <aop:aspect ref="logAspect" order="2"> <aop:before method="beforeLog" pointcut-ref="pointCut"/> <aop:after method="afterLog" pointcut-ref="pointCut"/> <aop:after-returning method="afterReturningLog" returning="result" pointcut-ref="pointCut"/> <aop:after-throwing method="afterThrowingLog" pointcut-ref="pointCut"/> </aop:aspect> <aop:aspect ref="transactionAspect" order="1"> <aop:around method="around" pointcut-ref="pointCut"/> </aop:aspect> </aop:config>
输出: 事物切面=======开启事务 日志切面前置通知...执行的目标方法为add传递给目标方法的参数值为[3, 4] 目标方法执行了 日志切面后置通知... 日志切面返回通知...目标方法的返回结果为7 事物切面=======提交事务
Spring的JdbcTemplate
1.导包
2.在applicationContext.xml文件中配置JdbcTemplate对象
<context:component-scan base-package="com.offcn"></context:component-scan> <context:property-placeholder location="classpath:jdbc.properties"/> <!--配置数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${jdbc.userName}"></property> <property name="password" value="${jdbc.password}"></property> <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property> <property name="driverClass" value="${jdbc.driverClass}"></property> </bean> <!--配置jdbcTemplate --> <bean class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean>
3.写实体类
4在Dao层使用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<Object[]> list = new ArrayList<Object[]>(); 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>(Employee.class), emp_id); } //查询单值 public double maxSalary() { String sql = "SELECT MAX(salary) FROM employee"; return jdbcTemplate.queryForObject(sql, Double.class); } //查询对象列表 public List<Employee> selectAll(){ String sql = "select * from employee"; return jdbcTemplate.query(sql, new BeanPropertyRowMapper<Employee>(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<Employee> list = employeeDao.selectAll(); for (Employee employee : list) { System.out.println(employee); } }
标签:int,void,Object,spring03,代理,笔记,随堂,emp,public 来源: https://www.cnblogs.com/bai3535/p/12061508.html