Spring学习 Spring注解开发、 使用Java方式配置Spring、静态代理模式、动态代理模式、AOP的实现方式

Spring注解开发

在spring4 后,使用注解开发就需要保证导入了aop包
并加入 context 的约束,增加注解的支持。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--注解的支持-->
    <!--扫描指定的包,包中的注解会生效-->
    <context:component-scan base-package="com.xmn"/>
    <context:annotation-config/>

</beans>

属性的注入

//相当于 <bean id="user" class="com.xmn.pojo.User"/>
@Component
public class User {
//    相当于 <property name="name" value="Xmn"/>
    @Value("Xmn")
    public String name;
}

衍生注解

@Component有几个衍生的注解,在web开发中,按照MVC分为三层。

  • dao【@Repository】
  • service【@Service】
  • controller【@Controller】
    这四个注解的功能都是将某个类注册到Spring中。

作用域

//相当于 <bean id="user" class="com.xmn.pojo.User"/>
@Component
//@Scope指定作用域 singleton指单例模式 prototype 指多实例
@Scope("singleton")
public class User {
//    相当于 <property name="name" value="Xmn"/>
    @Value("Xmn")
    public String name;
}

小结

XML 功能更强大,适用于任何场合,方便维护.
注解 只能使用自己类中的东西,维护复杂。
最好使用 xml 来管理bean,而注解只用来完成属性的注入。

使用Java方式配置Spring

不使用 XML文件配置Spring,全交给java来做,用到了javaconfig。

定义实体类:

//这个注解的意思是这个类被Spring接管了	
@Component
package com.xmn.pojo;

import org.springframework.beans.factory.annotation.Value;

public class User {
    private String name;

    public User(String name) {
        this.name = name;
    }

    @Value("xmn") //注入属性值
    public void setName(String name) {
        this.name = name;
    }

    public User() {
    }

    public String getName() {
        return name;
    }
}

创建一个config类

import com.xmn.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//@Configuration意为这是一个配置类
@Configuration
@Compomentscan(com.xmn.pojo)
public class Xmnconfig {

//  注册一个bean,相当于配置文件中的bean标签
//  方法的名字就是bean标签中的 id属性
//  方法的返回值就是bean标签中的class属性
    @Bean
    public User user(){
        return new User();
    }
}

代理模式

AOP的底层就是听过代理模式实现的。
代理模式分为静态代理和动态代理两种。

静态代理

角色分析:

  • 抽象角色:一般由接口和抽象类来实现
  • 真实角色:被代理的角色
  • 代理角色:代理别人的角色,用来做到一些操作
  • 客户:访问代理角色的人。

什么是静态代理呢?
两个对象之间的操作不直接进行,通过第三方进行代理来实现。比如房东要出租房子,那么房屋中介就是静态代理。
为什么需要静态代理呢?
对于房东出租房子,我们可以这样实现

package com.xmn.demo01;

public interface Rent {
    public void rent();
}
package com.xmn.demo01;

public class Host implements Rent{
    public void rent(){
        System.out.println("出租房子。");
    }
}

但是如果我们需要增加一些功能时,如果直接在源码上修改,很容易产生很多错误。而静态代理可以在不改变源码的基础上完成更改。

package com.xmn.demo01;

public class Proxy implements Rent{

    private Host host;

    public Proxy() {
    }

    public Proxy(Host host) {
        this.host = host;
    }

    public void rent() {
        seeHouse();
        host.rent();
    }

    public void seeHouse(){
        System.out.println("看房子");
    }
}

在出租房子之前可以增加一个看房子的流程,但是源码并没有被修改。

静态代理模式的优点:

  • 使真实角色更纯粹,不用关注公共业务。
  • 公共业务交给代理角色处理,实现业务分工。
  • 公共业务扩展方便集中管理。

静态代理模式的缺点:

每个真实角色都需要一个代理角色,代码量翻倍,开发效率降低。

动态代理

动态代理的角色与静态代理相同,真实角色,代理角色和抽象角色。
与静态代理不同的是,动态代理不用为每个真实角色编写代理角色,他通过InvocationHandler的实现类与反射包中的Proxy类来获取真实角色的代理角色。
测试代码如下:
抽象角色与真实角色:


package com.xmn.demo02;

public interface UserService {

    public void add();
    public void del();
    public void upd();
    public void que();
}

//----------------------------------------------------------------------------
package com.xmn.demo02;

public class UserServiceImpl implements UserService{

    public void add() {
        System.out.println("add");
    }

    public void del() {
        System.out.println("del");
    }

    public void upd() {
        System.out.println("upd");
    }

    public void que() {
        System.out.println("que");
    }


}

动态代理的实现:

package com.xmn.demo04;

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

public class ProxyInvocationHandler implements InvocationHandler {

    private Object target;

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

    public Object getTarget() {
        return target;
    }
	//获取代理类的方法
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

	//实现InvocationHandler接口后,需要实现invoke方法。
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());
        Object result = method.invoke(target, args);
        return result;
    }

    public void log(String msg){
        System.out.println("调用了"+ msg +"方法");
    }
}

使用代理的方法:

package com.xmn.demo04;

import com.xmn.demo02.UserService;
import com.xmn.demo02.UserServiceImpl;

public class Client {
    public static void main(String[] args) {

        UserServiceImpl userService = new UserServiceImpl();

        ProxyInvocationHandler pih = new ProxyInvocationHandler();

        pih.setTarget(userService);

        UserService proxy = (UserService) pih.getProxy();

        proxy.que();


    }

}

测试结果:
在这里插入图片描述

使用Spring实现AOP

在这里插入图片描述
在这里插入图片描述

需要导入依赖包

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>

1、使用Spring的API接口

环境搭建
定义UserService接口和他的实现类

package com.xmn.service;

public interface UserService {
    public void add();
    public void del();
    public void upd();
    public void que();
}
//-----------------------------------------------------------
public class UserServiceImpl implements UserService{

    public void add() {
        System.out.println("add");
    }

    public void del() {
        System.out.println("del");
    }

    public void upd() {
        System.out.println("upd");
    }

    public void que() {
        System.out.println("que");
    }
}

定义类实现Spring的API接口
想要在方法执行前插入的操作,写在Log类中
Log类实现 MethodBeforeAdvice 接口

package com.xmn.log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class Log implements MethodBeforeAdvice {
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName() +"的"+ method.getName()+"方法被执行了。");
    }
}

想要在方法执行后插入的操作,写在AfterLog类中
AfterLog类实现 AfterReturningAdvice 接口

package com.xmn.log;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class AfterLog implements AfterReturningAdvice {
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了 " + method.getName()+"方法,返回值为:"+returnValue );
    }
}

在配置文件中配置aop

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
        <!--注册bean-->
        <bean id="UserService" class="com.xmn.service.UserServiceImpl"/>
        <bean id="Log" class="com.xmn.log.Log"/>
        <bean id="AfterLog" class="com.xmn.log.AfterLog"/>
        <!--配置aop-->
        <aop:config>
            <!--切入点 expression:表达式   execution:要执行的位置-->
            <aop:pointcut id="pointcut" expression="execution(* com.xmn.service.UserServiceImpl.*(..))"/>
            <!--执行环绕增加-->
            <aop:advisor advice-ref="Log" pointcut-ref="pointcut"/>
            <aop:advisor advice-ref="AfterLog" pointcut-ref="pointcut"/>
        </aop:config>
</beans>

测试代码:

import com.xmn.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //动态代理代理的是接口 所以得到接口类型的 如果返回实现类类型,会报错
        UserService userService = context.getBean("UserService", UserService.class);

        userService.add();
    }
}

测试结果:
在这里插入图片描述

2、自定义类实现AOP

自定义切面

package com.xmn.diy;

public class DiyPointcut {
    public void before(){
        System.out.println("方法执行前");
    }
    public void after(){
        System.out.println("方法执行后");
    }
}

配置AOP

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="UserService" class="com.xmn.service.UserServiceImpl"/>
    <bean id="diy" class="com.xmn.diy.DiyPointcut"/>
    <aop:config>
    	<!--自定义的切面-->
        <aop:aspect ref="diy">
            <aop:pointcut id="pointcut" expression="execution(* com.xmn.service.UserServiceImpl.*(..))"/>
            <!--方法执行前-->
            <aop:before method="before" pointcut-ref="pointcut" />
            <!--方法执行后-->
            <aop:after method="after" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>

</beans>

测试代码:

import com.xmn.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //动态代理代理的是接口
        UserService userService = context.getBean("UserService", UserService.class);

        userService.add();
    }
}

运行结果
在这里插入图片描述

3、注解实现AOP

在配置文件中打开注解支持

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
        <!--注册bean-->
        <bean id="UserService" class="com.xmn.service.UserServiceImpl"/>
        <bean id="Log" class="com.xmn.log.Log"/>
        <bean id="AfterLog" class="com.xmn.log.AfterLog"/>

	    <!--方式三-->
	    <bean id="AnnotationPointcut" class="com.xmn.diy.AnnotationPointcut"/>
	    <!--开启注解支持-->
	    <aop:aspectj-autoproxy/>
    
</beans>

定义注解切入类

package com.xmn.diy;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect //标注切面
public class AnnotationPointcut {
    @Before("execution(* com.xmn.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("方法执行前");
    }
    @After("execution(* com.xmn.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("方法执行后");
    }

    //在环绕切入中,我们可以给定一个参数,来代表我们要获取的处理切入的点
    @Around("execution(* com.xmn.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前");

        //代表执行方法
        jp.proceed();

        System.out.println("环绕后");

    }

}

测试代码:

import com.xmn.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //动态代理代理的是接口
        UserService userService = context.getBean("UserService", UserService.class);

        userService.add();

    }
}

执行结果:
在这里插入图片描述
可见执行顺序为,环绕前,Before,环绕后,After。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值