AOP 类构造函数

本文介绍了一种使用.NET平台下的AOP(面向切面编程)技术实现的具体案例。通过自定义AopProxy类来实现对类方法的拦截,并在调用前后添加额外的功能,如显示消息框等。此示例展示了如何创建代理对象并调用其方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Activation;
using System.Windows.Forms;

using System.Runtime.Remoting;
using System.Runtime.Remoting.Services;
using EnterpriseServerBase.Aop.EnterpriseServerBase.Aop;
using EnterpriseServerBase.Aop;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //Example a = new Example("s");

            //a.say_hello();
            //a.sayByeBye("SSS");

            Aop.AopClass ac = new Aop.AopClass();
            ac.Hello();

            System.Console.Read();
        }

    }
}


namespace Aop
{
    public class AopAttribute : ProxyAttribute
    {
        public override MarshalByRefObject CreateInstance(Type serverType)
        {
            AopProxy realProxy = new AopProxy(serverType);
            return realProxy.GetTransparentProxy() as MarshalByRefObject;
        }


    }
}

namespace Aop
{
    public class AopProxy : RealProxy
    {
        public AopProxy(Type serverType)
            : base(serverType) { }

        public override IMessage Invoke(IMessage msg)
        {
            if (msg is IConstructionCallMessage)
            {
                IConstructionCallMessage constructCallMsg = msg as IConstructionCallMessage;
                IConstructionReturnMessage constructionReturnMessage = this.InitializeServerObject((IConstructionCallMessage)msg);
                RealProxy.SetStubData(this, constructionReturnMessage.ReturnValue);
                MessageBox.Show("Call constructor");
                return constructionReturnMessage;
            }
            else
            {
                IMethodCallMessage callMsg = msg as IMethodCallMessage;
                IMessage message;
                try
                {
                    object[] args = callMsg.Args;
                    object o = callMsg.MethodBase.Invoke(GetUnwrappedServer(), args);
                    message = new ReturnMessage(o, args, args.Length, callMsg.LogicalCallContext, callMsg);
                }
                catch (Exception e)
                {
                    message = new ReturnMessage(e, callMsg);
                }
                MessageBox.Show(message.Properties["__Return"].ToString());
                return message;
            }
        }
    }
}

namespace Aop
{
    [AopAttribute]
    public class AopClass : ContextBoundObject
    {
        public AopClass()
        {
            System.Console.WriteLine("SS");
        }

        public string Hello()
        {
            return "welcome";
        }

    }
}


<think>在Java中,尤其是在使用框架如Spring、Hibernate时,经常需要为实体提供空的构造函数(无参构造函数)。这是因为这些框架在创建对象实例时,通常通过反射调用无参构造函数来实例化对象,然后再通过setter方法或反射设置字段的值。 ### 为什么需要空的构造函数? 1. **反射实例化**:框架(如Spring)在创建Bean时,默认会调用无参构造函数。 2. **序列化/反序列化**:在对象序列化(如JSON转换)过程中,反序列化工具(如Jackson)需要先创建空对象再填充属性。 3. **ORM框架**:Hibernate/JPA在从数据库加载实体时,需要先通过无参构造创建实例,再通过反射设置字段。 ### 解决方案 #### 1. 显式添加无参构造 如果中没有定义任何构造函数,编译器会默认生成一个无参构造。但如果定义了带参构造,则必须显式添加无参构造。 ```java public class User { private Long id; private String name; // 显式添加无参构造函数 public User() { // 可以留空或进行初始化 } // 带参构造函数(可选) public User(Long id, String name) { this.id = id; this.name = name; } } ``` #### 2. Lombok注解(推荐) 使用Lombok的`@NoArgsConstructor`注解自动生成无参构造。 ```java import lombok.NoArgsConstructor; import lombok.AllArgsConstructor; @NoArgsConstructor // 生成无参构造 @AllArgsConstructor // 生成全参构造(可选) public class User { private Long id; private String name; } ``` #### 3. 与Jackson配合使用 当使用JSON库(如Jackson)反序列化时,需要无参构造。如果中没有无参构造,可以通过`@JsonCreator`和`@JsonProperty`来指定构造方法。 ```java public class User { private final Long id; private final String name; // 使用带参构造进行反序列化 @JsonCreator public User(@JsonProperty("id") Long id, @JsonProperty("name") String name) { this.id = id; this.name = name; } } ``` ### 注意事项 1. **访问权限**:无参构造的访问权限至少应该是包级私有(即不写访问修饰符)或public,否则框架可能无法访问。 2. **final字段**:如果中有final字段,且没有在声明时初始化,则必须通过构造函数初始化。此时,无参构造必须为final字段赋值(可以是null或默认值)。 3. **继承**:如果父没有无参构造,子必须显式调用父的有参构造。 ### 示例:解决数据库查询时的空构造问题 在使用JPA/Hibernate时,实体必须有无参构造。 ```java @Entity public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; // 必须有无参构造 public Employee() { } // 业务构造 public Employee(String name) { this.name = name; } } ``` ### 总结 - 当中定义了带参构造时,务必显式添加无参构造。 - 推荐使用Lombok的`@NoArgsConstructor`和`@AllArgsConstructor`简化代码。 - 在需要不可变对象时,考虑使用`@JsonCreator`配合带参构造。 §§相关问题§§: 1. 为什么Hibernate要求实体必须有无参构造? 2. 如何使用Lombok为实体生成构造器? 3. 在Jackson反序列化中,除了无参构造还有哪些方式? 4. 如何解决final字段与无参构造的冲突问题?</think>### 如何为 Java 添加空的构造函数 在 Java 开发中,特别是使用 Spring、JPA/Hibernate 等框架时,为实体和配置添加空的(无参)构造函数非常重要。以下是详细解决方案: #### 为什么需要空的构造函数? 1. **框架依赖**:Spring、Hibernate 等框架通过反射创建对象实例 2. **序列化/反序列化**:JSON 转换(Jackson/Gson)需要无参构造 3. **代理机制**:Spring AOP/CGLIB 动态代理需要无参构造 4. **JPA 规范**:实体必须有无参构造(public/protected) #### 解决方案与代码示例 ##### 1. 基本实体添加空构造 ```java @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String email; // 必须添加的空构造 public User() { // 可以留空或初始化默认值 } // 业务构造器(可选) public User(String name, String email) { this.name = name; this.email = email; } // Getter/Setter... } ``` ##### 2. 使用 Lombok 简化(推荐) ```java import lombok.NoArgsConstructor; import lombok.AllArgsConstructor; @Entity @NoArgsConstructor // 自动生成空构造 @AllArgsConstructor // 生成全参构造(可选) public class Product { @Id @GeneratedValue private Long id; private String name; private BigDecimal price; // 无需手动编写构造器 // Lombok 会在编译时自动生成 } ``` ##### 3. 继承场景下的空构造 ```java public class BaseEntity { @Id protected Long id; // 基需要空构造 protected BaseEntity() {} } @Entity public class Employee extends BaseEntity { private String department; // 子必须显式调用父构造 public Employee() { super(); // 必须调用父空构造 } } ``` ##### 4. 配置添加空构造 ```java @Configuration public class AppConfig { // 配置需要空构造 public AppConfig() { // 初始化逻辑... } @Bean public DataSource dataSource() { // 数据源配置 } } ``` ##### 5. 解决 Jackson 反序列化问题 ```java public class OrderDTO { private String orderId; private LocalDateTime createdDate; // 必须有无参构造 public OrderDTO() {} // 使用@JsonCreator处理复杂构造 @JsonCreator public OrderDTO(@JsonProperty("order_id") String orderId, @JsonProperty("created_at") long timestamp) { this.orderId = orderId; this.createdDate = Instant.ofEpochMilli(timestamp) .atZone(ZoneId.systemDefault()) .toLocalDateTime(); } } ``` #### 关键注意事项: 1. **访问修饰符**: - 公共:`public` 无参构造 - 实体:`protected` 也可接受(Hibernate 要求) 2. **final 字段处理**: ```java public class ImmutableConfig { private final String apiKey; // final字段需要在构造器中初始化 public ImmutableConfig() { this.apiKey = System.getenv("API_KEY"); } } ``` 3. **序列化框架兼容**: - Jackson:需要无参构造或 `@JsonCreator` - Gson:可以没有无参构造但推荐添加 4. **JPA 实体特殊要求**: - 无参构造必须是 `public` 或 `protected` - 不能是 `private` #### 最佳实践: 1. 始终为实体添加显式空构造 2. 使用 Lombok 的 `@NoArgsConstructor` 减少样板代码 3. 在单元测试中验证对象实例化: ```java @Test void shouldCreateEntityViaReflection() throws Exception { Class<?> clazz = User.class; Constructor<?> constructor = clazz.getDeclaredConstructor(); Object instance = constructor.newInstance(); assertNotNull(instance); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值