03spring

目录

动态代理

aop专业术语

前置通知 

后置通知

返回通知

异常通知

环绕通知:

公共切入点

xml配置aop

JdbcTemplate

搭建:

properties:

 JdbcTemplate.update(增删改) 数据更新

JdbcTemplate.batchUpdate(批量增删改)

JdbcTemplata.QueryForOBject获取信息

query查询

事务问题演示


动态代理

动态代理是java的一种设计模式。它的特征就是委托类和代理类具有相同的接口,代理类是在委托类的代码基础上添加了其他功能,比如消息预处理、消息过滤和事后处理消息等。但是实际上业务逻辑还是有委托类去完成的,简单来说,调用委托类的时候是通过代理对象来实现的。

代理类是在程序运行的时候 创建的所以被称为动态代理。动态代理相对于静态代理更加灵活,能够根据java代码指示动态生成

创建一个接口 作用是加减乘除

public interface MathI {

	int add(int i, int j);
	int sub(int i, int j);
	int mul(int i, int j);
	int div(int i, int j);
	
}

创建一个类来实现这个接口

public class MathImpl implements MathI {

	@Override
	public int add(int i, int j) {

		int result = i + j;

		return result;
	}

	@Override
	public int sub(int i, int j) {

		int result = i - j;

		return result;
	}

	@Override
	public int mul(int i, int j) {
		int result = i * j;
		return result;
	}

	@Override
	public int div(int i, int j) {
		System.out.println("method:div,arguments:"+i+","+j);
		int result = i / j;
		System.out.println("method:div,result:"+result);
		return result;
	}
	
}

创建一个工具类

public class Mylogger {
    public static void before(String methodName,String args){
        System.out.println("method:"+methodName+",arguments:"+args);

    }
    public static void after(String methodName,Object result){
        System.out.println("method:"+methodName+",result:"+result);

    }
}

创建一个动态代理的类

public class ProxyUtil {
	public ProxyUtil(MathImpl mathImpl) {
		this.mathImpl = mathImpl;
	}

	private MathImpl mathImpl;
	
	public Object getProxy() {
//获取当前类的加载器,用来加载代理对象实现所属类
		ClassLoader loader = this.getClass().getClassLoader();
//获取目标对象实现所有接口的class,代理类会和目标类实现相同的功能
		Class[] interfaces = mathImpl.getClass().getInterfaces();
		return Proxy.newProxyInstance(loader, interfaces, new InvocationHandler() {
			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				Mylogger.before(method.getName(), Arrays.toString(args));
				Object result=method.invoke(mathImpl, args);//动态代理对象实现功能
				Mylogger.after(method.getName(),result);
				return result;

			}
		});
	}
}

测试

public class Test {

	public static void main(String[] args) {
		
		ProxyUtil proxy=new ProxyUtil(new MathImpl());
		MathI math=(MathI) proxy.getProxy();
		int i=math.add(1,1);
		System.out.println(i);
		
	}
	
}

aop专业术语

  • Advice (增强/通知) 表示需要扩展的功能(前置通知,后置通知,返回通知,异常通知,环绕通知)。就是各个方法
  • JoinPoint (连接点) 表示允许使用增强的地方。基本每个方法的前、后或异常等都是连接点。也就是切面作用作用于目标对象方法中的位置
  • Pointcut (切入点) 表示实际增强的方法。切入点表达式(value = "execution(* aop.*.*(..))")
  • Aspect (切面) 表示扩展功能的过程。也就是把非核心业务放到一个类,这个类就叫切面
  • Introduction( 引入) 表示向现有的类中添加新方法、新属性。
  • Target (目标对象) 表示被增强的对象。
  • Proxy (代理) 表示实现AOP的机制。
  • Weaving (织入) 表示把增强应用到目标对象的过程。
  • 横切关注点:从每个方法中抽取出来的非核心业务,放到切面就叫通知

前置通知 

不管是什么通知 都要在放通知的类里面加

@Component//扫描组件
@Aspect//标注当前类为切面
@Order(1)//定义切面作用的优先级,值越小优先级越高,默认值为int的最大值

@Before:将方法设置为前置通知  必须设置value 其值表示切入点表达式

value="execution(属性类型 包名.类名.方法(形参列表类型))"

       Object[] args=joinPoint.getArgs();//获取方法参数
        String MethodName=joinPoint.getSignature().getName();//获取方法名

public class MyloggerAspect {
    //@Before(value = "execution(public int aop.MathImp.add(interestin,int))")//
    @Before(value = "execution(* aop.*.*(..))")//第一个个*代表任意的返回值类型,第二个*代表任意的类,第三个*代表任意的方法,..代表任意类型的参数
    public void beforeMethod(JoinPoint joinPoint){//JoinPoint 连接点
        Object[] args=joinPoint.getArgs();//获取方法参数
        String MethodName=joinPoint.getSignature().getName();//获取方法名
        System.out.println("MethodName:"+MethodName+",argsments:"+ Arrays.toString(args));
    }
}

后置通知

@after:将方法设置成后置通知,在方法执行之后运行

@After(value = "execution(* aop.*.*(..))")
    public void afterMethod(){
        System.out.println("后置通知");
    }

不管是前置通知还是后置通知 都要在放通知的类里面加

@Component//扫描组件
@Aspect//标注当前类为切面
@Order(1)//定义切面作用的优先级,值越小优先级越高,默认值为int的最大值

返回通知

@AfterReturning:将方法设置为返回通知,是在方法执行之后运行

可以通过returning设置接受方法返回值的变量 要想在方法中使用,必须要在方法的形参列表中设置和变量名相同的参数名的参数

@AfterReturning(value = "execution(public int aop.MathImpl.add(int,int))",returning = "result")
    public void afterreturning(JoinPoint joinPoint,Object result){
          String methodName=joinPoint.getSignature().getName();
          System.out.println("方法名字:"+methodName+"结果"+result);
    }

异常通知

@AfterThrowing(value = "execution(* aop.*.*(..))",throwing = "ex")
    public void afterthrowing(Exception ex){
        System.out.println("有异常了aaaaa,,异常信息:"+ex);
    }

@AfterThrowing:将方法设为异常通知,作用于方法抛出异常时

可通过throwing设置接受方法的异常信息

在参数列表中通过具体的异常类型(ArithmeticException ex)来对指定的异常信息进行操作

环绕通知:

环绕通知是所有通知类型中功能最为强大的, 能够全面地控制连接点. 甚至可以控制是否执行连接点.

@Around(value = "execution(* aop.*.*(..))")
    public Object arounemethod(ProceedingJoinPoint joinPoint){
        Object resutl=null;

        try {
            System.out.println("前置通知");
            joinPoint.proceed();//执行方法
            System.out.println("放回通知");
            return resutl;
        } catch (Throwable e) {
            System.out.println("异常通知");
            e.printStackTrace();
        }finally {
            System.out.println("后置通知");
        }
        return -1;
    }

公共切入点

@Pointcut:定义一个公共切入点

 @Pointcut(value = "execution(* aop.*.*(..))")
    public void test(){}
//后面要选择切入点直接用这个方法就行
@After(value = "test()")
    public void afterMethod(){
        System.out.println("后置通知");
    }

xml配置aop

<aop:config> 
    <!-- 声明切面,切面类id可以自己取,或者用系统默认的就是扫描类的首字母小写的类名 -->
    <aop:aspect ref="切面类id">
	    <!-- 抽取切点表达式 -->
        <aop:pointcut id="切点id" expression="切点表达式"/>
        <!-- 设置增强 -->
        <aop:增强方式 method="增强方法名" pointcut-ref="切点id"></aop:增强方式>
    </aop:aspect>
</aop:config>
<aop:config>
		<aop:aspect ref="myLogger">
			<aop:pointcut expression="execution(* com.atguigu.spring.aopxml.*.*(..))" id="cut"/>
			<!-- <aop:before method="before" pointcut="execution(* com.atguigu.spring.aopxml.*.*(..))"/> -->
			<aop:before method="before" pointcut-ref="cut"/>
		</aop:aspect>
	</aop:config>

JdbcTemplate

搭建:

<!-- 创建数据连接池,也就是数据源 -->
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
	  <property name="driverClassName" value="${jdbc.dirver}"></property>
	  <property name="url" value="${jdbc.url}"></property>
	  <property name="username" value="${jdbc.username}"></property>
	  <property name="password" value="${jdbc.passwors}"></property>
	</bean>
	
	<!--通过数据源配置jdbcTemplate ,其中ref就是数据源的id -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
	    <property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 引入属性文件,也就是为数据连接池里的赋值 -->
	<!--写法一:  -->
	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	   <property name="location" value="db.properties"></property>
	</bean>
	<!--写法二  -->
	<context:property-placeholder location="db.properties"/>

properties:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm
jdbc.username=root
jdbc.password=123456

 JdbcTemplate.update(增删改) 数据更新

	@Test
	public void test() {
		jdbcTemplate.update("insert into emp value(null,'张山',23,'男')");
		String sql="insert into emo value(null,?,?,?)";
		jdbcTemplate.update(sql, "李四",24,'女')
	}

JdbcTemplate.batchUpdate(批量增删改)

@Test
	public void testBatchUpdate() {
		String sql="insert into imp value(null,?,?,?')";
		List <Object[]>list=new ArrayList();
		list.add(new Object[]{"a1",24,'男'});
		list.add(new Object[] {"a2",25,'女'});
		jdbcTemplate.batchUpdate(sql,list)



        //批量删除
        String eids = "3,4,5";
		String sql = "delete from emp where eid in ("+eids+")";
		jdbcTemplate.update(sql);
	}

JdbcTemplata.QueryForOBject获取信息

	@Test
	public void testQueryForObject() {
	
    String sql="select eid,ename,age,sex,from emp where eid=?";
   RowMapper<Emp> rowMapper=new BeanPropertyRowMapper<Emp>(Emp.class);
   Emp queryForObject = jdbcTemplate.queryForObject(sql, new Object[] 
    {1},rowMapper); 
		System.out.println(queryForObject);//就可以打印eid=1的数据
		
	}

query查询

@Test
	public void testQuery() {
		String sql="select eid,ename,age,sex from emp";
		RowMapper<Emp> rowmapper=new BeanPropertyRowMapper<Emp>(Emp.class);
		List<Emp> list = jdbcTemplate.query(sql, rowmapper);
		for (Emp emp : list) {
			System.out.println(emp);
		}
	}

事务问题演示

事务时逻辑上紧密关联二合并成一个整体,这些操作要么都执行,要么都不执行

模拟买书:

创建daor层

public interface BookDao {

	Integer selectPrice(String bid);// 查询价格
	
	void updateSt(String bid);//更新买完后书的库存
	
	void updateBalance(String uid, Integer price);//更新余额
	
}
@Repository
public class BookDaoImpl implements BookDao {

	@Autowired
	private JdbcTemplate jdbcTemplate;//JdbcTemplate连接数据库

	@Override
	public Integer selectPrice(String bid) {
		Integer price = jdbcTemplate.queryForObject("select price from book where bid = ?", new Object[] {bid}, Integer.class);
		return price;

	}

	@Override
	public void updateSt(String bid) {
		//获取该书籍的库存
		Integer st = jdbcTemplate.queryForObject("select st from stock where sid = ?", new Object[] {bid}, Integer.class);
		if(st <= 0) {
			throw new RuntimeException();
		}else {
			jdbcTemplate.update("update stock set st = st -1 where sid = ?", bid);
		}
		
	}
  
	@Override
	public void updateBalance(String uid, Integer price) {
		Integer balance=jdbcTemplate.queryForObject("select balance from money where uid=?",new Object[] {uid},Integer.class);
		if(price>balance) {
			throw new MyException("余额不足");
		}else {
			jdbcTemplate.update("update money set balance=balance-? where uid=?",price,uid);
		}
	}
	
	
	
}

service层

public interface BookService {

	void buyBook(String bid, String uid);
	
}
@Service
public class BookServiceImpl implements BookService {
//seveice调用dao
	@Autowired
	private BookDao dao;

	public void buyBook(String bid, String uid) {
		Integer price = dao.selectPrice(bid);
		dao.updateSt(bid);
		dao.updateBalance(uid, price);
	}
}

controller层

@Controller
public class BookController {
//controller 调用sever
	@Autowired
	private BookService service;

	
	public void buyBook() {
		service.buyBook("1", "1001");
	}
	
	
}

测试

public class Test {

	public static void main(String[] args) {
		
		ApplicationContext ac = new ClassPathXmlApplicationContext("conf/book.xml");
		BookController controller = ac.getBean("bookController", BookController.class);
		controller.buyBook();
		
	}
	
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值