Java之Spring常用注解以及AOP详解

Spring注解

为什么需要注解配置

当我们的项目越来越复杂时 配置文件也会变得复杂影响开发效率 
所以Spring提供了注解方式来配置bean 

使用注解需要做的准备工作

1.添加Context命名空间 
    xmlns:context="http://www.springframework.org/schema/context"
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"
2.添加jar包 spring-aop-5.0.5.RELEASE.jar
3.扫描注解
    <context:component-scan base-package="包名"></context:component-scan>
    会扫描指定的包名下的所有子孙包

常用注解

@Component(只能加在类上)

例如:给User类加上该注解就等同于在配置文件添加了
    "user" class="com.lanou.entity.User">

如果没有指定bean的名字 默认是类名以小写开头
指定名字:Component("name")

Component的衍生标签
    Service         对应Service业务逻辑层
    Controller      对应Action/Servlet
    Repository      对应数据库相关(dao层)
这三个子标签作用和Component一样 但是更加语义化 更符合JavaEE分层思想

@Scope

用来控制bean的作用域
写法:
    @Scope(scopeName="singleton")

    singleton
    prototype
    request
    session

@Value 注入属性

可以写在属性上 也可以写在set方法上
写在属性上会破坏 对象的封装性 建议写在set方法上
例如:
    @Value("SC")
    public void setName(String name) {
        this.name = name;
    }

@AutoWired 和 @Qualifier

@AutoWired 自动装配 可以将容器中对应bean自动注入到属性中
@Qualifier 当容器有多个相同类型的bean 用它来指定具体装配哪一个 和Autowired搭配使用

例如:
    @Autowired
    @Qualifier("myHouse")
    private House house;

@Resource

手动装配 告诉Spring 把哪一个bean注入进来

例如:
    @Resource(name="myHouse")
    private House house;

@PostConstructor 和 @PreDestroy

@PostConstructor 加在方法上 对象构造后立即执行
@PreDestroy 加在方法上 对象销毁前执行

例如:
    @PostConstruct // 构造函数调用之后执行
    public void init() {
        System.out.println("前置方法");
    }
    @PreDestroy // 销毁之前执行的方法
    public void destroy() {
        System.out.println("后置方法");
    }

@After 和 @Before

@Before – 表示在任意使用@Test注解标注的public void方法执行之前执行
@After – 表示在任意使用@Test注解标注的public void方法执行之后执行

实例

public class SpringTest {

    ClassPathXmlApplicationContext ac;

    @After
    public void after() {
        System.out.println("测试代码后");
        ac.close();
    }
    @Before
    public void before() {
        System.out.println("测试代码前");
        ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    }

    @Test
    public void method1() {
        System.out.println(ac.getBean("person"));
    }
    @Test
    public void method2() {
        System.out.println(ac.getBean("myHouse"));
    }
}

Test环境 和 Web环境的区别

Test不会自动创建容器 所以无法使用@Autowired
web环境中Spring可以跟随项目启动

Spring与Junit整合测试

在测试环境 需要手动创建Spring容器 管理生命周期
SpringTest就是为了方便在测试环境容器出现的
1.导入jar包(spring-test-5.0.5.RELEASE.jar)
2.在测试类上添加 
    运行测试时 会自动创建Spring容器
    @RunWith(SpringJUnit4ClassRunner.class)
    指定配置文件
    @ContextConfiguration("classpath:applicationContext.xml")


// 运行测试时 会自动创建Spring容器
@RunWith(SpringJUnit4ClassRunner.class)
// 指定配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest2 {  
    @Resource(name="person1")
    Person person;
    @Test
    public void method() {
        System.out.println(person);
    }   
}

Spring AOP

AOP 全称面向切面编程
    是一种编程思想 就像OOP一样
    OOP的核心是类和对象
    AOP的核心是切面

    其实AOP说的简单点就是将公共代码进行抽取 集中编写
    例如:以前使用过的过滤器/拦截器 都是AOP思想

AOP名词解释

Joinpoint连接点        可以增强对象
Pointcut切入点         需要进行增强方法 
Advice 通知、增强代码
Target 目标对象 被代理对象
Weaving 织入 将通知应用到链接点的过程
代理 代理对象 
切面  切入点+通知

如何实现AOP(就是把增强代码插入原有代码)

1.动态代理 
    A对象需要被代理
    B对象来代理A
    本来直接调用A对象的方法
    现在换个方式 先调用B对象 B对象再去调用A对象
    被代理对象(A)必须实现某个接口
    注意:没有实现任何接口的对象无法代理 不能增强
2.cglib
    A对象需要被代理
    实现代码增强的原理
    会自动生成被代理类的子类对象
    生成一个A类的子类 代理
    注意:被final修饰的类不能被代理 不能进行增强

如果某个类既没有接口 又被final修饰 SpringAOP就搞不定 这时AspectJ就发挥作用了

例如

public class UserDaoImpl implements UserDao{

    @Override
    public void addUser(User user) {
        System.out.println("添加用户");
    }

    @Override
    public void deleteUser(User user) {
        System.out.println("删除用户");
    }

}

public class UserDaoImplProxy implements UserDao{
    // 真正要执行方法的对象
    private UserDao target;

    public UserDaoImplProxy(UserDao target) {
        this.target = target;
    }

    @Override
    public void addUser(User user) {
        // 添加增强代码
        System.out.println("设置编码");
        target.addUser(user);
    }

    @Override
    public void deleteUser(User user) {
        // 添加增强代码
        System.out.println("设置编码");
        target.deleteUser(user);
    }
}

使用SpringAOP来实现一个日志功能

UserDaoImpl

@Repository
public class UserDaoImpl implements UserDao{

    @Override
    public void addUser(User u) {
        System.out.println("添加用户");
    }

    @Override
    public void deleteUser(User u) {
        System.out.println("删除用户");
    }

}

MyAdvice 或 MyAroundAdvice

public class MyAdvice implements MethodBeforeAdvice,AfterReturningAdvice{
    // 前置通知 (前置增强)
    // 参数1 Method 要调用的原始方法
    // 参数2 Object[] 方法的参数
    // 参数3 Object 被代理对象 真正要执行方法的对象
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(new Date() + " " + target + " 执行了" + method.getName() + " 参数:" + Arrays.toString(args));

        //System.out.println("返回值" + object);
    }

    // 后置通知
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println(new Date() + " " + target +
                " 执行完毕" + method.getName() + " 参数:" + Arrays.toString(args) +
                " 返回值:" + returnValue);
    }
}
public class MyAroundAdvice implements MethodInterceptor{
    // 环绕通知 方法执行前后都可以增强
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object target = invocation.getThis();
        Object[] arguments = invocation.getArguments();
        Method method = invocation.getMethod();
        System.out.println("环绕增强前");
        // 环绕通知不会自动调用原始方法
        Object result = method.invoke(target, arguments);
        System.out.println("环绕增强后");
        return result;
    }
}

applicationContext.xml


<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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

    
    

    
    <bean name="advice" class="com.lanou.dao.impl.MyAroundAdvice">bean>

    <aop:config>
        
        <aop:pointcut expression="execution(* com.lanou.dao.impl.*DaoImpl.*(..))" id="point"/>
        
        <aop:advisor advice-ref="advice" pointcut-ref="point"/>
    aop:config>

    
    <context:component-scan base-package="com.lanou">context:component-scan>

beans>

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class MyTest {

    // 注入UserDao
    @Autowired
    private UserDao userDao;

    @Autowired
    private User user;

    @Test
    public void test() {
        userDao.addUser(user);
    }
}

你可能感兴趣的:(Java之Spring常用注解以及AOP详解)