springIOC和AOP注入、日志、代理、自定义类代替xml

ioc 控制反转
一个dao接口多个实现类,service层的实现类中创建了接口对象调用接口的方法,配置文件来决定该接口对象的实现类,通过实现类去调用实际的方法。

IOC DI注入

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--
    创建对象的第一种方式:利用无参构造器
    id:唯一标识符
    class:类的全类名
    name:起别名 可以支持起多个别名 用逗号 空格 分号隔开 可混合使用
    import:将多个配置文件合并
      -->
    <bean id="baseDaoImpl" class="com.lee.mapper.impl.BaseDaoImpl" name="baseDao"></bean>
    <bean id="userDaoImpl" class="com.lee.mapper.impl.UserDaoImpl" name="userDao"></bean>
    <!--BaseServiceImpl中有一个BaseDao 接口对象,但是没有还未赋值-->
    <bean id="baseServiceImpl" class="com.lee.service.impl.BaseServiceImpl">

        <!--给属性赋值 创建baseDaoImpl对象或者userDaoImpl,默认无参构造-->
        <property name="iBaseDao" ref="userDaoImpl"></property>

        <!--通过下标给有参构造赋值 前提是显示写出了有参构造-->
        <constructor-arg index="0" ref="userDaoImpl"></constructor-arg>

        <!--通过参数名给有参构造赋值 前提是显示写出了有参构造-->
        <constructor-arg name="iBaseDao" ref="userDaoImpl"></constructor-arg>
        <!--通过有参构造器参数个数注入 得显示写出来-->
        <constructor-arg  value="sss"/>
        <constructor-arg  value="sz"/>
    

        <!-- 不推荐使用 通过类型给有参构造赋值 前提是显示写出了有参构造-->
        <constructor-arg type="com.lee.mapper.IBaseDao" ref="baseDaoImpl"></constructor-arg>
    </bean>

    <!--给 id为userDaoImpl起别名为userDao-->
    <alias name="userDaoImpl" alias="userDao"></alias>



    <bean id="address" class="com.lee.entity.Address">
        <property name="address" value="西安"></property>
    </bean>
    //Student中有一个类属性 Address address;
    <bean id="student" class="com.lee.entity.Student" >

        <!--给student属性赋值-->
        <property name="name" value="zs"></property>
        <!--对象-->
        <property name="address" ref="address"></property>
        <!--数组-->
        <property name="books">
            <array>
                <value>红楼梦</value>
                <value>红楼梦</value>
            </array>
        </property>
        <!--list-->
        <property name="hobbys">
            <list>
                <value>游泳</value>
                <value>篮球</value>
            </list>
        </property>
        <!--set-->
        <property name="games">
            <set>
                <value>lol</value>
                <value>dota</value>
            </set>
        </property>

        <!--map-->
        <property name="card">
            <map>
                <entry key="身份证" value="111111"></entry>
                <entry key="银行卡" value="22222"></entry>
            </map>
        </property>
        <!--properties-->
        <property name="info">
            <props>
                <prop key="id">1190</prop>
                <prop key="school">xxxx</prop>
            </props>
        </property>
        <!--给空或空字符串-->
        <!--<property name="wife" value=""></property>-->
        <property name="wife">
            <null></null>
        </property>
        <!--c和p命名空间,c构造器注入,p属性注入 需要导入约束 了解即可-->
    </bean>

    <!--自动注入通过autowire 设置byName,通过名字自动注入,需要保证id和对象set方法的参数名一致
    byType 通过类型自动注入,可以没有id,但是类型重复就无法自动注入
    -->
    <bean id="dog" class="com.lee.entity.Dog"></bean>
    <bean id="people" class="com.lee.entity.People" autowire="byName">
        <property name="name" value="zs"></property>
        <!--通过属性注入-->
        <!--<property name="dog" ref="dog"></property>-->
    </bean>
</beans>

通过注解的方式注入

beans.xml

<?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"
       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.xsd">
    <!--哪些包可以识别到注解 -->
    <context:component-scan base-package="com.lee"></context:component-scan>
    
    <context:annotation-config/>
    <!--导入注解的约束和 <context:annotation-config/> -->
    <!--people类的dog属性加入@Autowired注解 通过byType方式注入-->
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
public class People {
    @Value("zs")
    private String name;
    private Integer age;
    
   //@Resource
   @Autowired
   @Qualifier(value = "dog22")
   //加入Qualifier相当于给dog取别名dog22,通过dog22找到id为dog22的bean
    private Dog dog;
    
}
public class Dog {

    public void shout(){
        System.out.println("wang~");
    }

}
<!--
     @Qualifier(value = "dog22")和Autowired注解一起使用 注入到下面的dog22,当名字不一致的时候使用
     此时Dog 属性名为 dog
     bean id="dog22" class="com.lee.entity.Dog"/>

     @Autowired里面的required设置为false代表可以为null

     @Nullable注解代表可以为null

     @Resource结合了spring的注解,先通过属性名字dog ,ref到id为dog的Dog类 没找到再通过类型注入
    等价于<property name="dog" ref="dog"/>

     @Scope("singleton")设置作用域为单例,默认单例 prototype为原型

    id作用用于getBean时的标识和ref寻找
    -->
    <bean id="dog" class="com.lee.entity.Dog" scope="singleton"></bean>
    <!--<bean id="dog22" class="com.lee.entity.Dog"></bean>-->
    <bean id="people" class="com.lee.entity.People"></bean>

    <!--使用spring注解开发代替bean 还需要导入扫描器
        <context:component-scan base-package="com.lee"></context:component-scan>
         @Component说明这个类被spring管理了
         @Value赋值
         dao层用@Repository
         service层用@Service
         Servlet层用@Controller-->

</beans>
@Test
    public void test2(){
        //通过new ClassPathXmlApplicationContext("beans.xml");实现配置文件
        ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
       //getBean(id唯一标识)
        People people = context.getBean("people", People.class);
        people.getDog().shout();
        System.out.println(people.toString());


    }

注解完全代替xml

需要定义一个JavaConfig类代替xml

//@Configuration注解定义一个配置类完全代替beans.xml,是一个JavaConfig
@Configuration
public class LeeConfig {

    /**
     *
     * @Bean等价于bean
     * 返回值类型 等价于class=com.lee.entity.Cat
     * 方法名 等价于id =getCat
     * 即 <bean id="getCat" class="com.lee.entity.Cat"></bean>
     */
    @Bean
    public Cat getCat(){
        return new Cat();
    }


}
@Component//定义这个类被spring管理
@ComponentScan("com.lee")//扫描器
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Cat {
    @Value("miao")
    private String name;
    @Value("18")
    private Integer age;

}
@Test
    public void testJavaConfig(){
        //通过new AnnotationConfigApplicationContext(LeeConfig.class); 实现JavaConfig
        ApplicationContext context = new AnnotationConfigApplicationContext(LeeConfig.class);
        //getBean(id唯一标识),在LeeConfig这个配置类中定义了
        Cat getCat = (Cat) context.getBean("getCat");
        System.out.println(getCat);

    }

AOP

代理实现:难点

public interface IBaseService {
    public void show();
}
@Data
public class BaseServiceImpl implements IBaseService {

    private IBaseDao iBaseDao=new BaseDaoImpl();

    public BaseServiceImpl() {
    }

    public BaseServiceImpl(IBaseDao iBaseDao) {
        this.iBaseDao = iBaseDao;
    }

    @Override
    public void show() {
        iBaseDao.show();
    }
}

IBaseService接口需要代理,BaseServiceImpl 是个真实对象,现在需要一个代理类去代理BaseServiceImpl
引入了一个InvocationHandler,去实现代理

public class ProxyInvocation implements InvocationHandler {
    //被代理的接口
    private IBaseService  baseService;
    //赋值
    public void setBaseService(IBaseService  baseService) {
        this.baseService= baseService;
    }

    //通过接口得到动态代理类的对象
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),baseService.getClass().getInterfaces(),this);
    }
    //自动调用这个invoke方法 返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(baseService,args);
    }
}
测试:
@Test
    public void test1(){
    //得到真实的对象
    BaseServiceImpl baseServiceImpl=new BaseServiceImpl();
    //得到类的对象
    ProxyInvocation pih = new ProxyInvocation();
    //给对象的代理接口赋值
    pih.setTarget(baseServiceImpl);
    //通过接口得到一个代理对象
    IBaseService proxy = (IBaseService) pih.getProxy();
    //代理对象调用方法
    proxy.show();
    
}

匿名内部类

@Test
    public void test(){

        //jdk的代理
         Host host=new HostImpl();
        InvocationHandler in=new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("发布信息");
                System.out.println("带人看房");
                host.hire();
                return null;

            }
        } ;
        Host o = (Host) Proxy.newProxyInstance(this.getClass().getClassLoader(), host.getClass().getInterfaces(),in);
        o.hire();

    }
    @Test
    public void test2(){

    Host host=new HostImpl();
        Enhancer enhancer=new Enhancer();
        enhancer.setSuperclass(HostImpl.class);
        enhancer.setCallback(new org.springframework.cglib.proxy.InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                System.out.println("发布信息");
                System.out.println("带人看房");
                host.hire();
                return null;
            }
        });
        Host o = (Host) enhancer.create();
        o.hire();

    }

通用方法

public class ProxyInvocation implements InvocationHandler {
    //被代理的接口
    private Object target;
    //赋值
    public void setTarget(Object target) {
        this.target = target;
    }

    //通过接口得到动态代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }
    //自动调用这个invoke方法 返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(target,args);
    }
}

AOP增强即面向切面

加入日志 pom里面需要配置
方式一
实现MethodBeforeAdvice

public class Log implements MethodBeforeAdvice {
//AfterReturningAdvice之后

    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("执行了"+method.getName());
        method.invoke(o,objects);
    }
}

xml需要配置

<?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
           http://www.springframework.org/schema/beans/spring-beans.xsd

            http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop.xsd">
           <!--扫描器 扫描哪些包下的注解-->
    <context:component-scan base-package="com.lee"></context:component-scan>
    <context:annotation-config/>
    <bean id="div" class="com.lee.entity.DivLog"></bean>
    <bean id="log" class="com.lee.entity.Log"></bean>
    <bean id="baseService" class="com.lee.service.impl.BaseServiceImpl"></bean>
    <!--log类继承 切入点 环绕-->
    <aop:config>
    //expression决定切入的哪个类 哪个方法 参数
        <aop:pointcut id="pointcut" expression="execution(* com.lee.service.impl.BaseServiceImpl.*(..))"></aop:pointcut>
        //advice-ref 引用的类 切入到哪里
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor>
    </aop:config>

自定义类日志


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

}
<bean id="div" class="com.lee.entity.DivLog"></bean>
    <bean id="log" class="com.lee.entity.Log"></bean>
    <bean id="baseService" class="com.lee.service.impl.BaseServiceImpl"></bean>
    <!--自定义log类 切面编程 切入点 切面-->
    <aop:config>
    //自定义的需要ref到类中
        <aop:aspect  ref="div">
        //id为pointcut expression决定切入的类 方法 参数
            <aop:pointcut id="pointcut" expression="execution(* com.lee.service.*.*(..))"></aop:pointcut>
            //方法执行之前 pointcut-ref决定切入的地方id
            <aop:before method="before" pointcut-ref="pointcut"></aop:before>
            <aop:after method="after" pointcut-ref="pointcut"></aop:after>
        </aop:aspect>
    </aop:config>

    <!--注解方式实现切面 加入注解即可@Aspect @Before @After 和@Before("execution(* *.*(..))")-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

注解的方式实现日志,需要在配置文件中把这个类配置好然后使用<aop:aspectj-autoproxy></aop:aspectj-autoproxy>即可

@Aspect
@Component
public class Log {
    //定义切入点
    @Pointcut("execution(* service.impl.UserServiceImpl.*(..))")
    public void a(){}

    @Before("a()")
    public void before(JoinPoint joinPoint){

        System.out.println("注解前置通知");
    }
    @AfterReturning(value = "a()",returning = "obj")
    public void after(JoinPoint joinpoint,Object obj){

        System.out.println("注解后置通知");

    }
    //异常通知
    @AfterThrowing(value = "a()",throwing = "ex")
    public void thr(JoinPoint joinPoint,Exception ex){

        System.out.println("异常通知");
    }
    //环绕通知
    @Around(value = "a()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

        System.out.println("环绕前置");
        //放行
        Object proceed = joinPoint.proceed();
        System.out.println("环绕后置");
        return proceed;
    }

}
@Test
    public void testAop(){
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    //因为加入了aop面向切面编程,使用了动态代理,所以要转成接口IBaseService而不是BaseServiceImpl,BaseServiceImpl会报错
//    BaseServiceImpl baseService = context.getBean("baseService", BaseServiceImpl.class);
        IBaseService baseService = context.getBean("baseService", IBaseService.class);
        baseService.show();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值